Skip to main content

hinge_rs/
models.rs

1use chrono::{DateTime, Utc};
2use serde::{Deserialize, Serialize, de::Deserializer};
3use serde_json::Value as JsonValue;
4
5use crate::enums::{
6    ChildrenStatusPreference, ChildrenStatusProfile, ContentType, DatingIntentionPreference,
7    DatingIntentionProfile, DrinkingStatusPreference, DrinkingStatusProfile, DrugStatusPreference,
8    DrugStatusProfile, EducationAttainedPreference, EducationAttainedProfile, EthnicityPreference,
9    EthnicityProfile, GenderEnum, GenderPreferences, MarijuanaStatusPreference,
10    MarijuanaStatusProfile, PoliticsPreference, PoliticsProfile, RelationshipTypePreference,
11    RelationshipTypeProfile, ReligionPreference, ReligionProfile, SmokingStatusPreference,
12    SmokingStatusProfile,
13};
14
15// Wrapper structs for status fields that include visibility
16#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
17#[derive(Clone, Debug, Serialize, Deserialize)]
18#[serde(rename_all = "camelCase")]
19pub struct ChildrenStatus {
20    pub value: ChildrenStatusProfile,
21    pub visible: bool,
22}
23
24#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
25#[derive(Clone, Debug, Serialize, Deserialize)]
26#[serde(rename_all = "camelCase")]
27pub struct DatingIntention {
28    pub value: DatingIntentionProfile,
29    pub visible: bool,
30}
31
32#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
33#[derive(Clone, Debug, Serialize, Deserialize)]
34#[serde(rename_all = "camelCase")]
35pub struct DrinkingStatus {
36    pub value: DrinkingStatusProfile,
37    pub visible: bool,
38}
39
40#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
41#[derive(Clone, Debug, Serialize, Deserialize)]
42#[serde(rename_all = "camelCase")]
43pub struct DrugStatus {
44    pub value: DrugStatusProfile,
45    pub visible: bool,
46}
47
48#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
49#[derive(Clone, Debug, Serialize, Deserialize)]
50#[serde(rename_all = "camelCase")]
51pub struct MarijuanaStatus {
52    pub value: MarijuanaStatusProfile,
53    pub visible: bool,
54}
55
56#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
57#[derive(Clone, Debug, Serialize, Deserialize)]
58#[serde(rename_all = "camelCase")]
59pub struct SmokingStatus {
60    pub value: SmokingStatusProfile,
61    pub visible: bool,
62}
63
64#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
65#[derive(Clone, Debug, Serialize, Deserialize)]
66#[serde(rename_all = "camelCase")]
67pub struct Religion {
68    pub value: Vec<ReligionProfile>,
69    pub visible: bool,
70}
71
72#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
73#[derive(Clone, Debug, Serialize, Deserialize)]
74#[serde(rename_all = "camelCase")]
75pub struct Politics {
76    pub value: PoliticsProfile,
77    pub visible: bool,
78}
79
80#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
81#[derive(Clone, Debug, Serialize, Deserialize)]
82#[serde(rename_all = "camelCase")]
83pub struct Pronouns {
84    pub value: Vec<i32>, // TODO: Define PronounsEnum once we know the values
85    pub visible: bool,
86}
87
88#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
89#[derive(Clone, Debug, Serialize, Deserialize)]
90#[serde(rename_all = "camelCase")]
91pub struct RelationshipTypeIds {
92    pub value: Vec<RelationshipTypeProfile>,
93    pub visible: bool,
94}
95
96#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
97#[derive(Clone, Debug, Serialize, Deserialize)]
98#[serde(rename_all = "camelCase")]
99pub struct Ethnicities {
100    pub value: Vec<EthnicityProfile>,
101    pub visible: bool,
102}
103
104#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
105#[derive(Clone, Debug, Serialize, Deserialize)]
106#[serde(rename_all = "camelCase")]
107pub struct Educations {
108    pub value: Vec<String>,
109    pub visible: bool,
110}
111
112#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
113#[derive(Clone, Debug, Serialize, Deserialize)]
114#[serde(rename_all = "camelCase")]
115pub struct SexualOrientations {
116    pub value: Vec<i32>, // TODO: Define proper enum
117    pub visible: bool,
118}
119
120#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
121#[derive(Clone, Debug, Serialize, Deserialize)]
122#[serde(rename_all = "camelCase")]
123pub struct Works {
124    pub value: String,
125    pub visible: bool,
126}
127
128#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
129#[derive(Clone, Debug, Serialize, Deserialize)]
130#[serde(rename_all = "camelCase")]
131pub struct FamilyPlans {
132    pub value: i32,
133    pub visible: bool,
134}
135
136#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
137#[derive(Clone, Debug, Serialize, Deserialize)]
138#[serde(rename_all = "camelCase")]
139pub struct GenderIdentityId {
140    pub value: i32,
141    pub visible: bool,
142}
143
144#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
145#[derive(Clone, Debug, Serialize, Deserialize)]
146#[serde(rename_all = "camelCase")]
147pub struct Hometown {
148    pub value: String,
149    pub visible: bool,
150}
151
152#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
153#[derive(Clone, Debug, Serialize, Deserialize)]
154#[serde(rename_all = "camelCase")]
155pub struct JobTitle {
156    pub value: String,
157    pub visible: bool,
158}
159
160#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
161#[derive(Clone, Debug, Serialize, Deserialize)]
162#[serde(rename_all = "camelCase")]
163pub struct LanguagesSpoken {
164    pub value: Vec<i32>, // Language enum IDs
165    pub visible: bool,
166}
167
168#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
169#[derive(Clone, Debug, Serialize, Deserialize)]
170#[serde(rename_all = "camelCase")]
171pub struct Zodiac {
172    pub value: i32, // Zodiac sign enum ID
173    pub visible: bool,
174}
175
176#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
177#[derive(Clone, Debug, Serialize, Deserialize)]
178#[serde(rename_all = "camelCase")]
179pub struct Location {
180    pub name: String,
181    #[serde(default, skip_serializing_if = "Option::is_none")]
182    pub latitude: Option<f64>,
183    #[serde(default, skip_serializing_if = "Option::is_none")]
184    pub longitude: Option<f64>,
185    #[serde(default, skip_serializing_if = "Option::is_none", rename = "metroArea")]
186    pub metro_area: Option<String>,
187    #[serde(
188        default,
189        skip_serializing_if = "Option::is_none",
190        rename = "metroAreaV2"
191    )]
192    pub metro_area_v2: Option<String>,
193    #[serde(
194        default,
195        skip_serializing_if = "Option::is_none",
196        rename = "countryShort"
197    )]
198    pub country_short: Option<String>,
199    #[serde(
200        default,
201        skip_serializing_if = "Option::is_none",
202        rename = "adminArea1Long"
203    )]
204    pub admin_area1_long: Option<String>,
205    #[serde(
206        default,
207        skip_serializing_if = "Option::is_none",
208        rename = "adminArea1Short"
209    )]
210    pub admin_area1_short: Option<String>,
211    #[serde(
212        default,
213        skip_serializing_if = "Option::is_none",
214        rename = "adminArea2"
215    )]
216    pub admin_area2: Option<String>,
217}
218
219#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
220#[derive(Clone, Debug, Serialize, Deserialize)]
221#[serde(rename_all = "camelCase")]
222pub struct HingeAuthToken {
223    pub identity_id: String,
224    pub token: String,
225    pub expires: DateTime<Utc>,
226}
227
228#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
229#[derive(Clone, Debug, Serialize, Deserialize)]
230#[serde(rename_all = "camelCase")]
231pub struct SendbirdAuthToken {
232    pub token: String,
233    pub expires: DateTime<Utc>,
234}
235
236#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
237#[derive(Clone, Debug, Serialize, Deserialize)]
238#[serde(rename_all = "camelCase")]
239pub struct LoginTokens {
240    #[serde(default)]
241    pub hinge_auth_token: Option<HingeAuthToken>,
242    #[serde(default)]
243    pub sendbird_auth_token: Option<SendbirdAuthToken>,
244}
245
246#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
247#[derive(Clone, Debug, Serialize, Deserialize)]
248#[serde(rename_all = "camelCase")]
249pub struct LikeLimit {
250    pub likes: i32,
251    #[serde(default)]
252    pub superlikes: Option<i32>,
253}
254
255#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
256#[derive(Clone, Debug, Serialize, Deserialize)]
257#[serde(rename_all = "camelCase")]
258pub struct RecommendationSubject {
259    pub subject_id: String,
260    pub rating_token: String,
261    #[serde(default)]
262    pub origin: Option<String>,
263}
264
265#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
266#[derive(Clone, Debug, Serialize, Deserialize)]
267#[serde(rename_all = "camelCase")]
268pub struct RecommendationsFeed {
269    pub id: i32,
270    pub origin: String,
271    pub subjects: Vec<RecommendationSubject>,
272    #[serde(default)]
273    pub permission: Option<String>,
274    #[serde(default)]
275    pub preview: Option<RecommendationsPreview>,
276}
277
278#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
279#[derive(Clone, Debug, Serialize, Deserialize)]
280#[serde(rename_all = "camelCase")]
281pub struct RecommendationsResponse {
282    pub feeds: Vec<RecommendationsFeed>,
283    #[serde(default)]
284    pub active_pills: Option<Vec<ActivePill>>,
285    #[serde(default)]
286    pub cache_control: Option<serde_json::Value>,
287}
288
289#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
290#[derive(Clone, Debug, Serialize, Deserialize)]
291#[serde(rename_all = "camelCase")]
292pub struct ProfileName {
293    pub first_name: String,
294    #[serde(default)]
295    pub last_name: Option<String>,
296}
297
298#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
299#[derive(Clone, Debug, Default, Serialize, Deserialize)]
300#[serde(rename_all = "camelCase")]
301pub struct Coordinate {
302    #[serde(default)]
303    pub x: f64,
304    #[serde(default)]
305    pub y: f64,
306}
307
308#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
309#[derive(Clone, Debug, Default, Serialize, Deserialize)]
310#[serde(rename_all = "camelCase")]
311pub struct BoundingBox {
312    #[serde(default)]
313    pub top_left: Coordinate,
314    #[serde(default)]
315    pub bottom_right: Coordinate,
316}
317
318#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
319#[derive(Clone, Debug, Serialize, Deserialize)]
320#[serde(rename_all = "camelCase")]
321pub struct Feedback {
322    pub evaluation: String,
323    pub detail: String,
324    pub feedback_token: String,
325}
326
327#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
328#[derive(Clone, Debug, Serialize, Deserialize)]
329#[serde(rename_all = "camelCase")]
330pub struct PhotoAsset {
331    #[serde(skip_serializing_if = "Option::is_none")]
332    pub id: Option<String>,
333    pub url: String,
334    #[serde(skip_serializing_if = "Option::is_none")]
335    pub cdn_id: Option<String>,
336    #[serde(skip_serializing_if = "Option::is_none")]
337    pub content_id: Option<String>,
338    #[serde(skip_serializing_if = "Option::is_none")]
339    pub prompt_id: Option<String>,
340    #[serde(skip_serializing_if = "Option::is_none")]
341    pub caption: Option<String>,
342    #[serde(skip_serializing_if = "Option::is_none")]
343    pub width: Option<i32>,
344    #[serde(skip_serializing_if = "Option::is_none")]
345    pub height: Option<i32>,
346    #[serde(skip_serializing_if = "Option::is_none")]
347    pub video_url: Option<String>,
348    #[serde(skip_serializing_if = "Option::is_none")]
349    pub selfie_verified: Option<bool>,
350    #[serde(skip_serializing_if = "Option::is_none")]
351    pub bounding_box: Option<BoundingBox>,
352    #[serde(skip_serializing_if = "Option::is_none")]
353    pub location: Option<String>,
354    #[serde(skip_serializing_if = "Option::is_none")]
355    pub source: Option<String>,
356    #[serde(skip_serializing_if = "Option::is_none")]
357    pub source_id: Option<String>,
358    #[serde(skip_serializing_if = "Option::is_none")]
359    pub p_hash: Option<String>,
360}
361
362#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
363#[derive(Clone, Debug, Serialize, Deserialize)]
364#[serde(rename_all = "camelCase")]
365pub struct ProfileAnswer {
366    #[serde(skip_serializing_if = "Option::is_none")]
367    pub prompt_id: Option<String>,
368    #[serde(skip_serializing_if = "Option::is_none")]
369    pub content: Option<String>,
370    #[serde(skip_serializing_if = "Option::is_none")]
371    pub content_id: Option<String>,
372    #[serde(skip_serializing_if = "Option::is_none")]
373    pub position: Option<i32>,
374    #[serde(skip_serializing_if = "Option::is_none")]
375    pub question_id: Option<String>,
376    #[serde(skip_serializing_if = "Option::is_none")]
377    pub response: Option<String>,
378    #[serde(skip_serializing_if = "Option::is_none", rename = "type")]
379    pub answer_type: Option<String>,
380    #[serde(skip_serializing_if = "Option::is_none")]
381    pub feedback: Option<Feedback>,
382    #[serde(skip_serializing_if = "Option::is_none")]
383    pub transcription_metadata: Option<JsonValue>,
384    #[serde(skip_serializing_if = "Option::is_none")]
385    pub url: Option<String>,
386    #[serde(skip_serializing_if = "Option::is_none")]
387    pub cdn_id: Option<String>,
388    #[serde(skip_serializing_if = "Option::is_none")]
389    pub waveform: Option<String>,
390    #[serde(skip_serializing_if = "Option::is_none")]
391    pub transcription: Option<String>,
392}
393
394#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
395#[derive(Clone, Debug, Serialize, Deserialize)]
396#[serde(rename_all = "camelCase")]
397pub struct PromptPoll {
398    pub content_id: String,
399    pub question_id: String,
400    pub options: Vec<String>,
401}
402
403#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
404#[derive(Clone, Debug, Serialize, Deserialize)]
405#[serde(rename_all = "camelCase")]
406pub struct VideoPrompt {
407    pub content_id: String,
408    pub question_id: String,
409    pub thumbnail_url: String,
410    pub video_url: String,
411    pub cdn_id: String,
412    pub bounding_box: BoundingBox,
413}
414
415#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
416#[derive(Clone, Debug, Serialize, Deserialize)]
417#[serde(rename_all = "camelCase")]
418pub struct ProfileContent {
419    pub name: ProfileName,
420    #[serde(default)]
421    pub photos: Vec<PhotoAsset>,
422    #[serde(default)]
423    pub answers: Vec<ProfileAnswer>,
424}
425
426#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
427#[derive(Clone, Debug, Serialize, Deserialize)]
428#[serde(rename_all = "camelCase")]
429pub struct Profile {
430    #[serde(skip_serializing_if = "Option::is_none")]
431    pub age: Option<i32>,
432    #[serde(skip_serializing_if = "Option::is_none")]
433    pub birthday: Option<String>,
434    #[serde(skip_serializing_if = "Option::is_none")]
435    pub covid_vax: Option<i32>,
436    #[serde(skip_serializing_if = "Option::is_none")]
437    pub children: Option<ChildrenStatus>,
438    #[serde(skip_serializing_if = "Option::is_none")]
439    pub dating_intention: Option<DatingIntention>,
440    #[serde(skip_serializing_if = "Option::is_none")]
441    pub dating_intention_text: Option<String>,
442    #[serde(skip_serializing_if = "Option::is_none")]
443    pub drinking: Option<DrinkingStatus>,
444    #[serde(skip_serializing_if = "Option::is_none")]
445    pub drugs: Option<DrugStatus>,
446    #[serde(skip_serializing_if = "Option::is_none")]
447    pub education_attained: Option<EducationAttainedProfile>,
448    #[serde(skip_serializing_if = "Option::is_none")]
449    pub educations: Option<Educations>,
450    #[serde(skip_serializing_if = "Option::is_none")]
451    pub email: Option<String>,
452    #[serde(skip_serializing_if = "Option::is_none")]
453    pub email_verified: Option<bool>,
454    #[serde(skip_serializing_if = "Option::is_none")]
455    pub ethnicities: Option<Ethnicities>,
456    #[serde(skip_serializing_if = "Option::is_none")]
457    pub ethnicities_text: Option<String>,
458    #[serde(skip_serializing_if = "Option::is_none")]
459    pub family_plans: Option<FamilyPlans>,
460    #[serde(rename = "firstName")]
461    pub first_name: String,
462    #[serde(skip_serializing_if = "Option::is_none")]
463    pub first_completed_date: Option<String>,
464    #[serde(skip_serializing_if = "Option::is_none")]
465    pub gender_id: Option<GenderEnum>,
466    #[serde(skip_serializing_if = "Option::is_none")]
467    pub gender_identity_id: Option<GenderIdentityId>,
468    #[serde(skip_serializing_if = "Option::is_none")]
469    pub gender_identity: Option<String>,
470    #[serde(skip_serializing_if = "Option::is_none")]
471    pub height: Option<i32>,
472    #[serde(skip_serializing_if = "Option::is_none")]
473    pub hometown: Option<Hometown>,
474    #[serde(skip_serializing_if = "Option::is_none")]
475    pub job_title: Option<JobTitle>,
476    #[serde(skip_serializing_if = "Option::is_none")]
477    pub languages_spoken: Option<LanguagesSpoken>,
478    #[serde(skip_serializing_if = "Option::is_none")]
479    pub last_name: Option<String>,
480    pub location: Location,
481    #[serde(skip_serializing_if = "Option::is_none")]
482    pub marijuana: Option<MarijuanaStatus>,
483    #[serde(skip_serializing_if = "Option::is_none")]
484    pub pets: Option<JsonValue>,
485    #[serde(skip_serializing_if = "Option::is_none")]
486    pub phone: Option<String>,
487    #[serde(skip_serializing_if = "Option::is_none")]
488    pub politics: Option<Politics>,
489    #[serde(skip_serializing_if = "Option::is_none")]
490    pub pronouns: Option<Pronouns>,
491    #[serde(skip_serializing_if = "Option::is_none")]
492    pub relationship_type_ids: Option<RelationshipTypeIds>,
493    #[serde(skip_serializing_if = "Option::is_none")]
494    pub relationship_types_text: Option<String>,
495    #[serde(skip_serializing_if = "Option::is_none")]
496    pub religions: Option<Religion>,
497    #[serde(skip_serializing_if = "Option::is_none")]
498    pub selfie_verified: Option<bool>,
499    #[serde(skip_serializing_if = "Option::is_none")]
500    pub sexual_orientations: Option<SexualOrientations>,
501    #[serde(skip_serializing_if = "Option::is_none")]
502    pub smoking: Option<SmokingStatus>,
503    #[serde(skip_serializing_if = "Option::is_none")]
504    pub works: Option<Works>,
505    #[serde(skip_serializing_if = "Option::is_none")]
506    pub zodiac: Option<Zodiac>,
507    #[serde(skip_serializing_if = "Option::is_none")]
508    pub last_active_status_id: Option<i32>,
509    #[serde(skip_serializing_if = "Option::is_none")]
510    pub did_just_join: Option<bool>,
511    // Content fields that might not be in the /user/v3 response
512    #[serde(skip_serializing_if = "Option::is_none")]
513    pub name: Option<ProfileName>,
514    #[serde(default)]
515    pub photos: Vec<PhotoAsset>,
516    #[serde(default)]
517    pub answers: Vec<ProfileAnswer>,
518}
519
520#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
521#[derive(Clone, Debug, Serialize, Deserialize)]
522#[serde(rename_all = "camelCase")]
523pub struct SelfProfileResponse {
524    pub user_id: String,
525    pub created: String,
526    pub registered: String,
527    pub modified: String,
528    pub last_active_opt_in: bool,
529    pub profile: Profile,
530    pub paused: bool,
531}
532
533#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
534#[derive(Clone, Debug, Serialize, Deserialize)]
535#[serde(rename_all = "camelCase")]
536pub struct ContentData {
537    #[serde(default)]
538    pub photos: Vec<PhotoAsset>,
539    #[serde(default)]
540    pub answers: Vec<ProfileAnswer>,
541    #[serde(skip_serializing_if = "Option::is_none")]
542    pub prompt_poll: Option<PromptPoll>,
543    #[serde(skip_serializing_if = "Option::is_none")]
544    pub video_prompt: Option<VideoPrompt>,
545}
546
547#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
548#[derive(Clone, Debug, Serialize, Deserialize)]
549#[serde(rename_all = "camelCase")]
550pub struct SelfContentResponse {
551    pub content: ContentData,
552}
553
554#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
555#[derive(Clone, Debug, Serialize, Deserialize)]
556#[serde(rename_all = "camelCase")]
557pub struct PreferencesResponse {
558    pub gendered_age_ranges: GenderedRange,
559    pub dealbreakers: Dealbreakers,
560    pub religions: Vec<ReligionPreference>,
561    pub drinking: Vec<DrinkingStatusPreference>,
562    pub gendered_height_ranges: GenderedRange,
563    pub marijuana: Vec<MarijuanaStatusPreference>,
564    pub relationship_types: Vec<RelationshipTypePreference>,
565    pub drugs: Vec<DrugStatusPreference>,
566    pub max_distance: i32,
567    pub children: Vec<ChildrenStatusPreference>,
568    pub ethnicities: Vec<EthnicityPreference>,
569    pub smoking: Vec<SmokingStatusPreference>,
570    pub education_attained: Vec<EducationAttainedPreference>,
571    pub family_plans: Vec<i32>,
572    pub dating_intentions: Vec<DatingIntentionPreference>,
573    pub politics: Vec<PoliticsPreference>,
574    pub gender_preferences: Vec<GenderPreferences>,
575}
576
577#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
578#[derive(Clone, Debug, Serialize, Deserialize)]
579#[serde(rename_all = "camelCase")]
580pub struct LikeResponse {
581    pub limit: LikeLimit,
582}
583
584// Rate respond (POST /rate/v2/respond)
585#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
586#[derive(Clone, Debug, Serialize, Deserialize)]
587#[serde(rename_all = "camelCase")]
588pub struct RateRespondRequest {
589    pub sort_type: String,
590    pub subject_id: String,
591    #[serde(default, skip_serializing_if = "Option::is_none")]
592    pub rating_id: Option<String>,
593    pub origin: String,
594    #[serde(default, skip_serializing_if = "Option::is_none")]
595    pub session_id: Option<String>,
596    #[serde(default, skip_serializing_if = "Option::is_none")]
597    pub initiated_with: Option<String>,
598    pub rating: String,
599    #[serde(default, skip_serializing_if = "Option::is_none")]
600    pub created: Option<String>,
601}
602
603#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
604#[derive(Clone, Debug, Serialize, Deserialize)]
605#[serde(rename_all = "camelCase")]
606pub struct RateRespondResponse {
607    #[serde(default)]
608    pub limit: Option<LikeLimit>,
609}
610
611// Likes v2 (recent likes feed)
612#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
613#[derive(Clone, Debug, Serialize, Deserialize)]
614#[serde(rename_all = "camelCase")]
615pub struct LikeRatingContentItem {
616    #[serde(default)]
617    pub photo: Option<PhotoAsset>,
618    #[serde(default)]
619    pub prompt: Option<CreateRateContentPrompt>,
620    #[serde(default)]
621    pub comment: Option<String>,
622    #[serde(default)]
623    pub prompt_poll: Option<LikePromptPoll>,
624}
625
626#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
627#[derive(Clone, Debug, Serialize, Deserialize)]
628#[serde(rename_all = "camelCase")]
629pub struct LikePromptPoll {
630    #[serde(default, skip_serializing_if = "Option::is_none")]
631    pub content_id: Option<String>,
632    pub options: Vec<String>,
633    pub question_id: String,
634    #[serde(default, skip_serializing_if = "Option::is_none")]
635    pub selected_option: Option<String>,
636    #[serde(default, skip_serializing_if = "Option::is_none")]
637    pub selected_option_index: Option<i32>,
638}
639
640// Match note response
641#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
642#[derive(Clone, Debug, Serialize, Deserialize)]
643#[serde(rename_all = "camelCase")]
644pub struct MatchNoteResponse {
645    pub note: String,
646}
647
648#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
649#[derive(Clone, Debug, Serialize, Deserialize)]
650#[serde(rename_all = "camelCase")]
651pub struct LikeRating {
652    #[serde(default)]
653    pub content: Vec<LikeRatingContentItem>,
654}
655
656#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
657#[derive(Clone, Debug, Serialize, Deserialize)]
658#[serde(rename_all = "camelCase")]
659pub struct LikeItemV2 {
660    pub player_id: String,
661    pub subject_id: String,
662    pub created: String,
663    pub source: String,
664    pub initiated_with: String,
665    pub rating: LikeRating,
666}
667
668#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
669#[derive(Clone, Debug, Serialize, Deserialize)]
670#[serde(rename_all = "camelCase")]
671pub struct LikeSortV2 {
672    pub id: String,
673    pub title: String,
674}
675
676#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
677#[derive(Clone, Debug, Serialize, Deserialize)]
678#[serde(rename_all = "camelCase")]
679pub struct SortedLikeIdV2 {
680    pub id: String,
681}
682
683#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
684#[derive(Clone, Debug, Serialize, Deserialize)]
685#[serde(rename_all = "camelCase")]
686pub struct SortedLikesGroupV2 {
687    #[serde(rename = "sortID")]
688    pub sort_id: String,
689    pub data: Vec<SortedLikeIdV2>,
690}
691
692#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
693#[derive(Clone, Debug, Serialize, Deserialize)]
694#[serde(rename_all = "camelCase")]
695pub struct LikesV2Response {
696    pub likes: Vec<LikeItemV2>,
697    #[serde(default)]
698    pub hidden_likes: Vec<JsonValue>,
699    #[serde(default)]
700    pub sorts: Vec<LikeSortV2>,
701    #[serde(default)]
702    pub sorted_likes: Vec<SortedLikesGroupV2>,
703}
704
705#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
706#[derive(Clone, Debug, Serialize, Deserialize)]
707#[serde(rename_all = "camelCase")]
708pub struct PublicProfile {
709    #[serde(skip_serializing_if = "Option::is_none")]
710    pub age: Option<i32>,
711    #[serde(skip_serializing_if = "Option::is_none")]
712    pub birthday: Option<String>,
713    #[serde(skip_serializing_if = "Option::is_none")]
714    pub covid_vax: Option<i32>,
715    #[serde(skip_serializing_if = "Option::is_none")]
716    pub children: Option<i32>, // Direct value, not wrapper
717    #[serde(skip_serializing_if = "Option::is_none")]
718    pub dating_intention: Option<i32>, // Direct value
719    #[serde(skip_serializing_if = "Option::is_none")]
720    pub dating_intention_text: Option<String>,
721    #[serde(skip_serializing_if = "Option::is_none")]
722    pub drinking: Option<i32>, // Direct value
723    #[serde(skip_serializing_if = "Option::is_none")]
724    pub drugs: Option<i32>, // Direct value
725    #[serde(skip_serializing_if = "Option::is_none")]
726    pub education_attained: Option<EducationAttainedProfile>,
727    #[serde(skip_serializing_if = "Option::is_none")]
728    pub educations: Option<Vec<String>>, // Direct array
729    #[serde(skip_serializing_if = "Option::is_none")]
730    pub email: Option<String>,
731    #[serde(skip_serializing_if = "Option::is_none")]
732    pub email_verified: Option<bool>,
733    #[serde(skip_serializing_if = "Option::is_none")]
734    pub ethnicities: Option<Vec<i32>>, // Direct array
735    #[serde(skip_serializing_if = "Option::is_none")]
736    pub ethnicities_text: Option<String>,
737    #[serde(skip_serializing_if = "Option::is_none")]
738    pub family_plans: Option<i32>, // Direct value
739    #[serde(rename = "firstName")]
740    pub first_name: String,
741    #[serde(skip_serializing_if = "Option::is_none")]
742    pub first_completed_date: Option<String>,
743    #[serde(skip_serializing_if = "Option::is_none")]
744    pub gender_id: Option<GenderEnum>,
745    #[serde(skip_serializing_if = "Option::is_none")]
746    pub gender_identity_id: Option<i32>, // Direct value
747    #[serde(skip_serializing_if = "Option::is_none")]
748    pub gender_identity: Option<String>,
749    #[serde(skip_serializing_if = "Option::is_none")]
750    pub height: Option<i32>,
751    #[serde(skip_serializing_if = "Option::is_none")]
752    pub hometown: Option<String>, // Direct string
753    #[serde(skip_serializing_if = "Option::is_none")]
754    pub job_title: Option<String>, // Direct string
755    #[serde(skip_serializing_if = "Option::is_none")]
756    pub languages_spoken: Option<Vec<i32>>, // Direct array
757    #[serde(skip_serializing_if = "Option::is_none")]
758    pub last_name: Option<String>,
759    pub location: Location, // Same structure
760    #[serde(skip_serializing_if = "Option::is_none")]
761    pub marijuana: Option<i32>, // Direct value
762    #[serde(skip_serializing_if = "Option::is_none")]
763    pub pets: Option<Vec<i32>>, // Direct array
764    #[serde(skip_serializing_if = "Option::is_none")]
765    pub phone: Option<String>,
766    #[serde(skip_serializing_if = "Option::is_none")]
767    pub politics: Option<i32>, // Direct value
768    #[serde(skip_serializing_if = "Option::is_none")]
769    pub pronouns: Option<Vec<i32>>, // Direct array
770    #[serde(skip_serializing_if = "Option::is_none")]
771    pub relationship_type_ids: Option<Vec<i32>>, // Direct array
772    #[serde(skip_serializing_if = "Option::is_none")]
773    pub relationship_types_text: Option<String>,
774    #[serde(skip_serializing_if = "Option::is_none")]
775    pub religions: Option<Vec<i32>>, // Direct array
776    #[serde(rename = "selfieVerified")]
777    pub selfie_verified: Option<bool>,
778    #[serde(skip_serializing_if = "Option::is_none")]
779    pub sexual_orientations: Option<Vec<i32>>, // Direct array
780    #[serde(skip_serializing_if = "Option::is_none")]
781    pub smoking: Option<i32>, // Direct value
782    #[serde(skip_serializing_if = "Option::is_none")]
783    pub works: Option<String>, // Direct string
784    #[serde(skip_serializing_if = "Option::is_none")]
785    pub zodiac: Option<i32>, // Direct value
786    #[serde(skip_serializing_if = "Option::is_none")]
787    pub last_active_status_id: Option<i32>,
788    #[serde(skip_serializing_if = "Option::is_none", alias = "didjustJoin")]
789    pub did_just_join: Option<bool>,
790}
791
792#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
793#[derive(Clone, Debug, Serialize, Deserialize)]
794#[serde(rename_all = "camelCase")]
795pub struct PublicUserProfile {
796    pub user_id: String,
797    pub profile: PublicProfile,
798}
799
800#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
801#[derive(Clone, Debug, Serialize, Deserialize)]
802#[serde(rename_all = "camelCase")]
803pub struct UserProfile {
804    pub user_id: String,
805    pub profile: JsonValue,
806}
807
808#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
809#[derive(Clone, Debug, Serialize, Deserialize)]
810#[serde(rename_all = "camelCase")]
811pub struct ProfileContentContent {
812    pub photos: Vec<PhotoAsset>,
813    pub answers: Vec<ProfileAnswer>,
814    #[serde(default)]
815    pub prompt_poll: Option<PromptPoll>,
816    #[serde(default)]
817    pub video_prompt: Option<VideoPrompt>,
818}
819
820#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
821#[derive(Clone, Debug, Serialize, Deserialize)]
822#[serde(rename_all = "camelCase")]
823pub struct ProfileContentFull {
824    pub user_id: String,
825    pub content: ProfileContentContent,
826}
827
828#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
829#[derive(Clone, Debug, Serialize, Deserialize)]
830#[serde(rename_all = "camelCase")]
831pub struct CreateRateContentPrompt {
832    pub answer: String,
833    #[serde(default, skip_serializing_if = "Option::is_none")]
834    pub content_id: Option<String>,
835    pub question: String,
836}
837
838#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
839#[derive(Clone, Debug, Serialize, Deserialize)]
840#[serde(rename_all = "camelCase")]
841pub struct CreateRateContent {
842    #[serde(skip_serializing_if = "Option::is_none")]
843    pub comment: Option<String>,
844    #[serde(skip_serializing_if = "Option::is_none")]
845    pub photo: Option<PhotoAsset>,
846    #[serde(skip_serializing_if = "Option::is_none")]
847    pub prompt: Option<CreateRateContentPrompt>,
848}
849
850#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
851#[derive(Clone, Debug, Serialize, Deserialize)]
852#[serde(rename_all = "camelCase")]
853pub struct CreateRate {
854    pub rating_id: String,
855    #[serde(skip_serializing_if = "Option::is_none")]
856    pub hcm_run_id: Option<String>,
857    pub session_id: String,
858    #[serde(skip_serializing_if = "Option::is_none")]
859    pub content: Option<CreateRateContent>,
860    // RFC3339 without subseconds, ending with Z
861    pub created: String,
862    pub rating_token: String,
863    #[serde(skip_serializing_if = "Option::is_none")]
864    pub initiated_with: Option<String>,
865    // "like" | "note" | "skip"
866    pub rating: String,
867    #[serde(default)]
868    pub has_pairing: bool,
869    #[serde(skip_serializing_if = "Option::is_none")]
870    pub origin: Option<String>,
871    pub subject_id: String,
872}
873
874#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
875#[derive(Clone, Debug, Serialize, Deserialize)]
876#[serde(rename_all = "camelCase")]
877pub struct VoiceAnswerPayload {
878    pub cdn_url: String,
879    pub waveform: String,
880    #[serde(rename = "type")]
881    pub answer_type: String,
882    pub cdn_id: String,
883    pub url: String,
884}
885
886#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
887#[derive(Clone, Debug, Serialize, Deserialize)]
888#[serde(rename_all = "camelCase")]
889pub struct AnswerContentPayload {
890    pub position: i32,
891    pub question_id: String,
892    #[serde(skip_serializing_if = "Option::is_none")]
893    pub text_answer: Option<JsonValue>,
894    #[serde(skip_serializing_if = "Option::is_none")]
895    pub voice_answer: Option<VoiceAnswerPayload>,
896}
897
898#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
899#[derive(Clone, Debug, Serialize, Deserialize)]
900#[serde(rename_all = "camelCase")]
901pub struct AnswerEvaluateRequest {
902    pub answer: String,
903    pub prompt_id: String,
904}
905
906#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
907#[derive(Clone, Debug, Serialize, Deserialize)]
908#[serde(rename_all = "camelCase")]
909pub struct CreatePromptPollRequest {
910    pub options: Vec<String>,
911    pub question_id: String,
912}
913
914#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
915#[derive(Clone, Debug, Serialize, Deserialize)]
916#[serde(rename_all = "camelCase")]
917pub struct CreatePromptPollResponse {
918    pub content_id: String,
919}
920
921#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
922#[derive(Clone, Debug, Serialize, Deserialize)]
923#[serde(rename_all = "camelCase")]
924pub struct CreateVideoPromptRequest {
925    pub question_id: String,
926    pub thumbnail_url: String,
927    pub cdn_id: String,
928    pub bounding_box: BoundingBox,
929    pub video_url: String,
930    pub source: String,
931    pub length_seconds: i32,
932}
933
934#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
935#[derive(Clone, Debug, Serialize, Deserialize)]
936#[serde(rename_all = "camelCase")]
937pub struct CreateVideoPromptResponse {
938    pub content_id: String,
939}
940
941#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
942#[derive(Clone, Debug, Serialize, Deserialize)]
943#[serde(rename_all = "camelCase")]
944pub struct Prompt {
945    pub id: String,
946    pub prompt: String,
947    pub is_selectable: bool,
948    #[serde(default)]
949    pub placeholder: String,
950    pub is_new: bool,
951    #[serde(default)]
952    pub categories: Vec<String>,
953    #[serde(default)]
954    pub content_types: Vec<ContentType>,
955}
956
957#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
958#[derive(Clone, Debug, Serialize, Deserialize)]
959#[serde(rename_all = "camelCase")]
960pub struct PromptCategory {
961    pub name: String,
962    pub slug: String,
963    pub is_visible: bool,
964    pub is_new: bool,
965}
966
967#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
968#[derive(Clone, Debug, Serialize, Deserialize)]
969#[serde(rename_all = "camelCase")]
970pub struct PromptsResponse {
971    pub prompts: Vec<Prompt>,
972    pub categories: Vec<PromptCategory>,
973}
974
975// Preferences DTOs
976#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
977#[derive(Clone, Debug, Serialize, Deserialize)]
978#[serde(rename_all = "camelCase")]
979pub struct RangeDetails {
980    pub max: Option<i32>,
981    pub min: Option<i32>,
982}
983
984#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
985#[derive(Clone, Debug, Serialize, Deserialize)]
986pub struct GenderedRange {
987    #[serde(rename = "0")]
988    pub men: Option<RangeDetails>,
989    #[serde(rename = "1")]
990    pub women: Option<RangeDetails>,
991    #[serde(rename = "3")]
992    pub non_binary_people: Option<RangeDetails>,
993}
994
995#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
996#[derive(Clone, Debug, Default, Serialize, Deserialize)]
997#[serde(rename_all = "camelCase")]
998pub struct RecsV2Params {
999    #[serde(default)]
1000    pub new_here: bool,
1001    #[serde(default)]
1002    pub active_today: bool,
1003}
1004
1005#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
1006#[derive(Clone, Debug, Serialize, Deserialize)]
1007#[serde(rename_all = "camelCase")]
1008pub struct ActivePill {
1009    pub pill_type: String,
1010    pub permission: String,
1011    pub id: String,
1012}
1013
1014#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
1015#[derive(Clone, Debug, Serialize, Deserialize)]
1016#[serde(rename_all = "camelCase")]
1017pub struct RecommendationsPreview {
1018    pub subjects: Vec<RecommendationSubject>,
1019    pub permission: String,
1020}
1021
1022#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
1023#[derive(Clone, Debug, Serialize, Deserialize)]
1024pub struct GenderedDealbreaker {
1025    #[serde(rename = "0")]
1026    pub men: Option<bool>,
1027    #[serde(rename = "1")]
1028    pub women: Option<bool>,
1029    #[serde(rename = "3")]
1030    pub non_binary_people: Option<bool>,
1031}
1032
1033#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
1034#[derive(Clone, Debug, Serialize, Deserialize)]
1035#[serde(rename_all = "camelCase")]
1036pub struct Dealbreakers {
1037    pub marijuana: bool,
1038    pub smoking: bool,
1039    pub max_distance: bool,
1040    pub drinking: bool,
1041    pub education_attained: bool,
1042    pub gendered_height: GenderedDealbreaker,
1043    pub politics: bool,
1044    pub relationship_types: bool,
1045    pub drugs: bool,
1046    pub dating_intentions: bool,
1047    pub family_plans: bool,
1048    pub gendered_age: GenderedDealbreaker,
1049    pub religions: bool,
1050    pub ethnicities: bool,
1051    pub children: bool,
1052}
1053
1054#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
1055#[derive(Clone, Debug, Serialize, Deserialize)]
1056#[serde(rename_all = "camelCase")]
1057pub struct Preferences {
1058    pub gendered_age_ranges: GenderedRange,
1059    pub dealbreakers: Dealbreakers,
1060    pub religions: Vec<ReligionPreference>,
1061    pub drinking: Vec<DrinkingStatusPreference>,
1062    pub gendered_height_ranges: GenderedRange,
1063    pub marijuana: Vec<MarijuanaStatusPreference>,
1064    pub relationship_types: Vec<RelationshipTypePreference>,
1065    pub drugs: Vec<DrugStatusPreference>,
1066    pub max_distance: i32,
1067    pub children: Vec<ChildrenStatusPreference>,
1068    pub ethnicities: Vec<EthnicityPreference>,
1069    pub smoking: Vec<SmokingStatusPreference>,
1070    pub education_attained: Vec<EducationAttainedPreference>,
1071    pub family_plans: Vec<i32>, // TODO: Define proper enum
1072    pub dating_intentions: Vec<DatingIntentionPreference>,
1073    pub politics: Vec<PoliticsPreference>,
1074    pub gender_preferences: Vec<GenderPreferences>,
1075}
1076
1077// Profile update DTOs
1078#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
1079#[derive(Clone, Debug, Serialize, Deserialize)]
1080#[serde(rename_all = "camelCase")]
1081pub struct ProfileUpdate {
1082    #[serde(skip_serializing_if = "Option::is_none")]
1083    pub children: Option<ChildrenStatus>,
1084    #[serde(skip_serializing_if = "Option::is_none")]
1085    pub dating_intention: Option<DatingIntention>,
1086    #[serde(skip_serializing_if = "Option::is_none")]
1087    pub drinking: Option<DrinkingStatus>,
1088    #[serde(skip_serializing_if = "Option::is_none")]
1089    pub drugs: Option<DrugStatus>,
1090    #[serde(skip_serializing_if = "Option::is_none")]
1091    pub marijuana: Option<MarijuanaStatus>,
1092    #[serde(skip_serializing_if = "Option::is_none")]
1093    pub smoking: Option<SmokingStatus>,
1094    #[serde(skip_serializing_if = "Option::is_none")]
1095    pub politics: Option<Politics>,
1096    #[serde(skip_serializing_if = "Option::is_none")]
1097    pub religions: Option<Religion>,
1098    #[serde(skip_serializing_if = "Option::is_none")]
1099    pub ethnicities: Option<Ethnicities>,
1100    #[serde(skip_serializing_if = "Option::is_none")]
1101    pub education_attained: Option<EducationAttainedProfile>,
1102    #[serde(skip_serializing_if = "Option::is_none")]
1103    pub relationship_type_ids: Option<RelationshipTypeIds>,
1104    #[serde(skip_serializing_if = "Option::is_none")]
1105    pub height: Option<i32>,
1106    #[serde(skip_serializing_if = "Option::is_none")]
1107    pub gender_id: Option<GenderEnum>,
1108    #[serde(skip_serializing_if = "Option::is_none")]
1109    pub hometown: Option<Hometown>,
1110    #[serde(skip_serializing_if = "Option::is_none")]
1111    pub languages_spoken: Option<LanguagesSpoken>,
1112    #[serde(skip_serializing_if = "Option::is_none")]
1113    pub zodiac: Option<Zodiac>,
1114}
1115
1116// Shared DTOs for RSPC inputs
1117#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
1118#[derive(Clone, Debug, Serialize, Deserialize)]
1119#[serde(rename_all = "camelCase")]
1120pub struct SkipInput {
1121    pub subject_id: String,
1122    pub rating_token: String,
1123    #[serde(default)]
1124    pub origin: Option<String>,
1125}
1126
1127#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
1128#[derive(Clone, Debug, Serialize, Deserialize)]
1129#[serde(rename_all = "camelCase")]
1130pub struct PhotoAssetInput {
1131    pub url: String,
1132    #[serde(skip_serializing_if = "Option::is_none")]
1133    pub content_id: Option<String>,
1134    #[serde(skip_serializing_if = "Option::is_none")]
1135    pub cdn_id: Option<String>,
1136    #[serde(skip_serializing_if = "Option::is_none")]
1137    pub bounding_box: Option<BoundingBox>,
1138    #[serde(skip_serializing_if = "Option::is_none")]
1139    pub selfie_verified: Option<bool>,
1140}
1141
1142#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
1143#[derive(Clone, Debug, Serialize, Deserialize)]
1144#[serde(rename_all = "camelCase")]
1145pub struct RateInput {
1146    pub subject_id: String,
1147    pub rating_token: String,
1148    #[serde(default)]
1149    pub origin: Option<String>,
1150    #[serde(default)]
1151    pub use_superlike: Option<bool>,
1152    #[serde(default)]
1153    pub photo: Option<PhotoAssetInput>,
1154    #[serde(default)]
1155    pub answer_text: Option<String>,
1156    #[serde(default)]
1157    pub question_text: Option<String>,
1158    #[serde(default)]
1159    pub content_id: Option<String>,
1160    #[serde(default)]
1161    pub comment: Option<String>,
1162}
1163
1164// Additional models from reverse engineering
1165
1166#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
1167#[derive(Clone, Debug, Serialize, Deserialize)]
1168#[serde(rename_all = "camelCase")]
1169pub struct UserSettings {
1170    pub is_smart_photo_opt_in: bool,
1171}
1172
1173#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
1174#[derive(Clone, Debug, Serialize, Deserialize)]
1175#[serde(rename_all = "camelCase")]
1176pub struct AuthSettings {
1177    pub apple_authed: bool,
1178    pub facebook_authed: bool,
1179    pub google_authed: bool,
1180    pub sms_authed: bool,
1181}
1182
1183#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
1184#[derive(Clone, Debug, Serialize, Deserialize)]
1185#[serde(rename_all = "camelCase")]
1186pub struct NotificationSettings {
1187    pub email: std::collections::HashMap<String, bool>,
1188    pub push: std::collections::HashMap<String, bool>,
1189}
1190
1191#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
1192#[derive(Clone, Debug, Serialize, Deserialize)]
1193#[serde(rename_all = "camelCase")]
1194pub struct UserTrait {
1195    pub id: String,
1196    pub user_input: String,
1197}
1198
1199#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
1200#[derive(Clone, Debug, Serialize, Deserialize)]
1201#[serde(rename_all = "camelCase")]
1202pub struct AccountInfo {
1203    pub subscription: JsonValue,
1204    pub account: std::collections::HashMap<String, bool>,
1205}
1206
1207#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
1208#[derive(Clone, Debug, Serialize, Deserialize)]
1209#[serde(rename_all = "camelCase")]
1210pub struct ExportStatus {
1211    pub status: String,
1212    pub created: Option<String>,
1213    pub url: Option<String>,
1214}
1215
1216// Rate/Like models
1217#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
1218#[derive(Clone, Debug, Serialize, Deserialize)]
1219#[serde(rename_all = "camelCase")]
1220pub struct RatePayload {
1221    pub rating_id: String,
1222    pub rating_token: String,
1223    pub subject_id: String,
1224    pub session_id: String,
1225    pub rating: String,
1226    pub origin: String,
1227    pub has_pairing: bool,
1228    pub created: String,
1229    pub initiated_with: String,
1230    pub content: Option<RateContentPayload>,
1231}
1232
1233#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
1234#[derive(Clone, Debug, Serialize, Deserialize)]
1235#[serde(rename_all = "camelCase")]
1236pub struct RateContentPayload {
1237    pub comment: Option<String>,
1238    pub photo: Option<JsonValue>,
1239    pub prompt: Option<JsonValue>,
1240}
1241
1242// Message models
1243#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
1244#[derive(Clone, Debug, Serialize, Deserialize)]
1245#[serde(rename_all = "camelCase")]
1246pub struct SendMessagePayload {
1247    #[serde(default, skip_serializing_if = "Option::is_none")]
1248    pub dedup_id: Option<String>,
1249    pub ays: bool,
1250    pub match_message: bool,
1251    pub message_type: String,
1252    pub message_data: MessageData,
1253    pub subject_id: String,
1254    pub origin: String,
1255}
1256
1257#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
1258#[derive(Clone, Debug, Serialize, Deserialize)]
1259#[serde(rename_all = "camelCase")]
1260pub struct MessageData {
1261    pub message: String,
1262}
1263
1264// Standouts models
1265#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
1266#[derive(Clone, Debug, Serialize, Deserialize)]
1267#[serde(rename_all = "camelCase")]
1268pub struct StandoutMediaRef {
1269    pub content_id: String,
1270}
1271
1272#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
1273#[derive(Clone, Debug, Serialize, Deserialize)]
1274#[serde(rename_all = "camelCase")]
1275pub struct StandoutContent {
1276    #[serde(default)]
1277    pub photo: Option<StandoutMediaRef>,
1278    #[serde(default)]
1279    pub prompt: Option<StandoutMediaRef>,
1280}
1281
1282#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
1283#[derive(Clone, Debug, Serialize, Deserialize)]
1284#[serde(rename_all = "camelCase")]
1285pub struct StandoutItem {
1286    pub subject_id: String,
1287    pub rating_token: String,
1288    pub content: StandoutContent,
1289}
1290
1291#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
1292#[derive(Clone, Debug, Serialize, Deserialize)]
1293#[serde(rename_all = "camelCase")]
1294pub struct StandoutsResponse {
1295    pub status: String,
1296    #[serde(default)]
1297    pub expiration: Option<String>,
1298    #[serde(default)]
1299    pub standouts: Vec<StandoutItem>,
1300}
1301
1302// Sendbird messages
1303#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
1304#[derive(Clone, Debug, Serialize, Deserialize)]
1305#[serde(rename_all = "snake_case")]
1306pub struct SendbirdMessageMetaItem {
1307    pub key: String,
1308    pub value: Vec<String>,
1309}
1310
1311#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
1312#[derive(Clone, Debug, Serialize, Deserialize)]
1313#[serde(rename_all = "snake_case")]
1314pub struct SendbirdMessageUser {
1315    pub user_id: String,
1316    #[serde(default)]
1317    pub profile_url: String,
1318    #[serde(default)]
1319    pub require_auth_for_profile_image: bool,
1320    #[serde(default)]
1321    pub nickname: String,
1322    #[serde(default)]
1323    pub metadata: JsonValue,
1324    #[serde(default)]
1325    pub role: String,
1326    #[serde(default)]
1327    pub is_active: bool,
1328    #[serde(default)]
1329    pub is_blocked_by_me: bool,
1330}
1331
1332#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
1333#[derive(Clone, Debug, Serialize, Deserialize)]
1334#[serde(rename_all = "snake_case")]
1335pub struct SendbirdMessage {
1336    #[serde(rename = "type")]
1337    pub msg_type: String,
1338    #[serde(deserialize_with = "de_num_to_string")]
1339    pub message_id: String,
1340    #[serde(default)]
1341    pub message: String,
1342    #[serde(default)]
1343    pub data: String,
1344    #[serde(default)]
1345    pub custom_type: String,
1346    #[serde(default)]
1347    pub file: JsonValue,
1348    #[serde(deserialize_with = "de_num_to_string")]
1349    pub created_at: String,
1350    pub user: SendbirdMessageUser,
1351    pub channel_url: String,
1352    #[serde(default, deserialize_with = "de_num_to_string")]
1353    pub updated_at: String,
1354    #[serde(default, deserialize_with = "de_num_to_string")]
1355    pub message_survival_seconds: String,
1356    #[serde(default)]
1357    pub mentioned_users: Vec<JsonValue>,
1358    #[serde(default)]
1359    pub mention_type: String,
1360    #[serde(default)]
1361    pub silent: bool,
1362    #[serde(default, deserialize_with = "de_num_to_string")]
1363    pub message_retention_hour: String,
1364    #[serde(default)]
1365    pub channel_type: String,
1366    #[serde(default)]
1367    pub translations: JsonValue,
1368    #[serde(default)]
1369    pub sorted_metaarray: Vec<SendbirdMessageMetaItem>,
1370    #[serde(default)]
1371    pub is_removed: bool,
1372    #[serde(default)]
1373    pub is_op_msg: bool,
1374    #[serde(default)]
1375    pub reactions_summary: Vec<JsonValue>,
1376    #[serde(default)]
1377    pub message_events: JsonValue,
1378}
1379
1380#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
1381#[derive(Clone, Debug, Serialize, Deserialize)]
1382#[serde(rename_all = "snake_case")]
1383pub struct SendbirdMessagesResponse {
1384    pub messages: Vec<SendbirdMessage>,
1385}
1386
1387#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
1388#[derive(Clone, Debug, Serialize, Deserialize)]
1389#[serde(rename_all = "snake_case")]
1390pub struct SendbirdChannelMember {
1391    #[serde(default)]
1392    pub user_id: String,
1393    #[serde(default)]
1394    pub nickname: String,
1395    #[serde(default)]
1396    pub profile_url: String,
1397    #[serde(default)]
1398    pub metadata: JsonValue,
1399    #[serde(default)]
1400    pub is_active: bool,
1401}
1402
1403#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
1404#[derive(Clone, Debug, Serialize, Deserialize)]
1405#[serde(rename_all = "snake_case")]
1406pub struct SendbirdGroupChannel {
1407    pub channel_url: String,
1408    #[serde(default)]
1409    pub name: String,
1410    #[serde(default)]
1411    pub cover_url: String,
1412    #[serde(default)]
1413    pub member_count: i32,
1414    #[serde(default)]
1415    pub joined_member_count: i32,
1416    #[serde(default)]
1417    pub unread_message_count: i32,
1418    #[serde(default)]
1419    pub members: Vec<SendbirdChannelMember>,
1420    #[serde(default)]
1421    pub metadata: JsonValue,
1422    #[serde(default)]
1423    pub custom_type: String,
1424    #[serde(default)]
1425    pub my_member_state: String,
1426    #[serde(default, deserialize_with = "de_num_to_string")]
1427    pub created_at: String,
1428    #[serde(default, deserialize_with = "de_num_to_string")]
1429    pub updated_at: String,
1430    #[serde(default)]
1431    pub last_message: Option<SendbirdMessage>,
1432}
1433
1434#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
1435#[derive(Clone, Debug, Serialize, Deserialize)]
1436#[serde(rename_all = "snake_case")]
1437pub struct SendbirdChannelsResponse {
1438    #[serde(default)]
1439    pub channels: Vec<SendbirdGroupChannel>,
1440}
1441
1442#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
1443#[derive(Clone, Debug, Serialize, Deserialize)]
1444#[serde(rename_all = "camelCase")]
1445pub struct SendbirdChannelsInput {
1446    #[serde(default)]
1447    pub limit: Option<i32>,
1448}
1449
1450#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
1451#[derive(Clone, Debug, Serialize, Deserialize)]
1452#[serde(rename_all = "camelCase")]
1453pub struct ExportChatInput {
1454    pub channel_url: String,
1455    pub output_dir: String,
1456    #[serde(default)]
1457    pub include_media: bool,
1458    #[serde(default, skip_serializing_if = "Option::is_none")]
1459    pub initiation_summary_lines: Option<Vec<String>>,
1460}
1461
1462#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
1463#[derive(Clone, Debug, Serialize, Deserialize)]
1464#[serde(rename_all = "camelCase")]
1465pub struct ExportedMediaFile {
1466    pub message_id: String,
1467    pub file_name: String,
1468    pub file_path: String,
1469}
1470
1471#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
1472#[derive(Clone, Debug, Serialize, Deserialize)]
1473#[serde(rename_all = "camelCase")]
1474pub struct ExportChatResult {
1475    pub folder_path: String,
1476    pub transcript_path: String,
1477    #[serde(default)]
1478    pub profile_path: Option<String>,
1479    pub message_count: i32,
1480    pub media_files: Vec<ExportedMediaFile>,
1481}
1482
1483#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
1484#[derive(Clone, Debug, Serialize, Deserialize)]
1485#[serde(rename_all = "camelCase")]
1486pub struct ConnectionPrompt {
1487    #[serde(default)]
1488    pub question: String,
1489    #[serde(default)]
1490    pub answer: String,
1491    #[serde(skip_serializing_if = "Option::is_none")]
1492    pub content_id: Option<String>,
1493}
1494
1495#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
1496#[derive(Clone, Debug, Serialize, Deserialize)]
1497#[serde(rename_all = "camelCase")]
1498pub struct ConnectionVideo {
1499    #[serde(default)]
1500    pub url: String,
1501    #[serde(default)]
1502    pub thumbnail: String,
1503    #[serde(skip_serializing_if = "Option::is_none")]
1504    pub bounding_box: Option<BoundingBox>,
1505    #[serde(skip_serializing_if = "Option::is_none")]
1506    pub cdn_id: Option<String>,
1507    #[serde(skip_serializing_if = "Option::is_none")]
1508    pub content_id: Option<String>,
1509}
1510
1511#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
1512#[derive(Clone, Debug, Serialize, Deserialize)]
1513#[serde(rename_all = "camelCase")]
1514pub struct ConnectionContentItem {
1515    #[serde(skip_serializing_if = "Option::is_none")]
1516    pub prompt: Option<ConnectionPrompt>,
1517    #[serde(skip_serializing_if = "Option::is_none")]
1518    pub photo: Option<PhotoAsset>,
1519    #[serde(skip_serializing_if = "Option::is_none")]
1520    pub video: Option<ConnectionVideo>,
1521    #[serde(skip_serializing_if = "Option::is_none")]
1522    pub comment: Option<String>,
1523}
1524
1525#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
1526#[derive(Clone, Debug, Serialize, Deserialize)]
1527#[serde(rename_all = "camelCase")]
1528pub struct ConnectionItem {
1529    #[serde(default)]
1530    pub initiator_id: String,
1531    #[serde(default)]
1532    pub subject_id: String,
1533    #[serde(default)]
1534    pub sent_content: Vec<ConnectionContentItem>,
1535    #[serde(skip_serializing_if = "Option::is_none")]
1536    pub sent_time: Option<String>,
1537    #[serde(skip_serializing_if = "Option::is_none")]
1538    pub received_time: Option<String>,
1539    #[serde(default)]
1540    pub source: String,
1541    #[serde(default)]
1542    pub initiated_with: String,
1543    #[serde(skip_serializing_if = "Option::is_none")]
1544    pub social_media_exchanged_timestamp: Option<String>,
1545    #[serde(default)]
1546    pub is_hidden: bool,
1547}
1548
1549#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
1550#[derive(Clone, Debug, Serialize, Deserialize)]
1551#[serde(rename_all = "camelCase")]
1552pub struct ConnectionDetailApi {
1553    #[serde(flatten)]
1554    pub connection: ConnectionItem,
1555    #[serde(
1556        default,
1557        rename = "showMatchNote",
1558        skip_serializing_if = "Option::is_none"
1559    )]
1560    pub show_match_note: Option<bool>,
1561}
1562
1563#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
1564#[derive(Clone, Debug, Serialize, Deserialize)]
1565#[serde(rename_all = "camelCase")]
1566pub struct ConnectionsResponse {
1567    #[serde(default)]
1568    pub connections: Vec<ConnectionItem>,
1569    #[serde(default)]
1570    pub your_turn_match_limit: i32,
1571}
1572
1573#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
1574#[derive(Clone, Debug, Serialize, Deserialize)]
1575#[serde(rename_all = "camelCase")]
1576pub struct SendbirdChannelHandle {
1577    pub channel_url: String,
1578}
1579
1580#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
1581#[derive(Clone, Debug, Serialize, Deserialize)]
1582#[serde(rename_all = "camelCase")]
1583pub struct SendbirdGetMessagesInput {
1584    pub channel_url: String,
1585    pub message_ts: String,
1586    pub prev_limit: i32,
1587}
1588
1589// Sendbird WebSocket READ response models
1590#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
1591#[derive(Clone, Debug, Serialize, Deserialize)]
1592pub struct SendbirdReadUser {
1593    pub name: String,
1594    pub image: String,
1595    pub require_auth_for_profile_image: bool,
1596    pub guest_id: String,
1597    #[serde(deserialize_with = "de_num_to_string")]
1598    pub id: String,
1599    pub role: String,
1600    #[serde(default)]
1601    pub metadata: JsonValue,
1602    pub is_bot: bool,
1603    pub is_ai_bot: bool,
1604    pub is_active: bool,
1605}
1606
1607#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
1608#[derive(Clone, Debug, Serialize, Deserialize)]
1609pub struct SendbirdReadResponse {
1610    #[serde(deserialize_with = "de_num_to_string")]
1611    pub channel_id: String,
1612    pub user: SendbirdReadUser,
1613    #[serde(deserialize_with = "de_num_to_string")]
1614    pub ts: String,
1615    #[serde(deserialize_with = "de_num_to_string")]
1616    pub sts: String,
1617    pub channel_url: String,
1618    pub channel_type: String,
1619    pub is_super: bool,
1620    pub target_parent_message_id: Option<String>,
1621    pub req_id: String,
1622}
1623
1624// Sendbird WebSocket SYEV (system event) models
1625#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
1626#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
1627pub struct SendbirdSyevUserData {
1628    pub user_id: String,
1629    #[serde(default)]
1630    pub nickname: String,
1631    #[serde(default)]
1632    pub profile_url: String,
1633    #[serde(default)]
1634    pub require_auth_for_profile_image: bool,
1635    #[serde(default)]
1636    pub metadata: JsonValue,
1637}
1638
1639#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
1640#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
1641pub struct SendbirdSyevEvent {
1642    #[serde(default)]
1643    pub channel_id: Option<String>,
1644    pub cat: i32,
1645    #[serde(default)]
1646    pub data: Option<SendbirdSyevUserData>,
1647    #[serde(default, deserialize_with = "de_num_to_string")]
1648    pub sts: String,
1649    #[serde(default, deserialize_with = "de_num_to_string")]
1650    pub ts: String,
1651    pub channel_url: String,
1652    pub channel_type: String,
1653    #[serde(default)]
1654    pub is_super: bool,
1655    #[serde(default)]
1656    pub is_access_code_required: bool,
1657    #[serde(default)]
1658    pub has_bot: bool,
1659    #[serde(default)]
1660    pub has_ai_bot: bool,
1661}
1662
1663impl SendbirdSyevEvent {
1664    pub const CATEGORY_TYPING_START: i32 = 10900;
1665    pub const CATEGORY_TYPING_END: i32 = 10901;
1666}
1667
1668// Sendbird Close request (for JS-side WS close)
1669#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
1670#[derive(Clone, Debug, Serialize, Deserialize)]
1671pub struct SendbirdCloseRequest {
1672    #[serde(default)]
1673    pub code: Option<u16>,
1674    #[serde(default)]
1675    pub reason: Option<String>,
1676}
1677
1678// Allow numbers or strings to deserialize into String
1679fn de_num_to_string<'de, D>(deserializer: D) -> Result<String, D::Error>
1680where
1681    D: Deserializer<'de>,
1682{
1683    let v = serde_json::Value::deserialize(deserializer)?;
1684    match v {
1685        serde_json::Value::String(s) => Ok(s),
1686        serde_json::Value::Number(n) => Ok(n.to_string()),
1687        serde_json::Value::Null => Ok(String::new()),
1688        other => Err(serde::de::Error::custom(format!(
1689            "expected string or number, got {}",
1690            other
1691        ))),
1692    }
1693}