shared/domain/
jig.rs

1//! Types for JIGs.
2pub mod curation;
3
4pub mod report;
5use macros::make_path_parts;
6pub use report::{JigReport, ReportId};
7
8pub mod codes;
9
10pub mod player;
11pub use player::{JigPlayerSettings, TextDirection};
12
13use chrono::{DateTime, Utc};
14use serde::{Deserialize, Serialize};
15use std::collections::{HashMap, HashSet};
16
17use super::{
18    additional_resource::AdditionalResource,
19    asset::{DraftOrLive, OrderBy, PrivacyLevel, UserOrMe},
20    category::CategoryId,
21    meta::{AffiliationId, AgeRangeId, ResourceTypeId},
22    module::LiteModule,
23    playlist::PlaylistResponse,
24    user::UserId,
25};
26use crate::domain::UpdateNonNullable;
27use crate::{api::endpoints::PathPart, domain::module::body::ThemeId};
28
29wrap_uuid! {
30    /// Wrapper type around [`Uuid`], represents the ID of a JIG.
31    pub struct JigId
32}
33
34make_path_parts!(JigCreatePath => "/v1/jig");
35
36/// Request to create a new JIG.
37///
38/// This creates the draft and live [JigData](JigData) copies with the requested info.
39#[derive(Serialize, Deserialize, Debug, Default)]
40#[serde(rename_all = "camelCase")]
41pub struct JigCreateRequest {
42    /// The JIG's name.
43    #[serde(default)]
44    pub display_name: String,
45
46    /// This JIG's age ranges.
47    #[serde(skip_serializing_if = "Vec::is_empty")]
48    #[serde(default)]
49    pub age_ranges: Vec<AgeRangeId>,
50
51    /// This jig's affiliations.
52    #[serde(skip_serializing_if = "Vec::is_empty")]
53    #[serde(default)]
54    pub affiliations: Vec<AffiliationId>,
55
56    /// The language the jig uses.
57    ///
58    /// NOTE: in the format `en`, `eng`, `en-US`, `eng-US` or `eng-USA`. To be replaced with a struct that enforces this.
59    #[serde(default)]
60    pub language: String,
61
62    /// The jig's categories.
63    #[serde(skip_serializing_if = "Vec::is_empty")]
64    #[serde(default)]
65    pub categories: Vec<CategoryId>,
66
67    /// Description of the jig. Defaults to empty string.
68    #[serde(default)]
69    pub description: String,
70
71    /// Default player settings for this jig.
72    #[serde(default)]
73    pub default_player_settings: JigPlayerSettings,
74}
75
76/// The over-the-wire representation of a JIG's data. This can either be the live copy or the draft copy.
77#[derive(Serialize, Deserialize, Clone, Debug)]
78#[serde(rename_all = "camelCase")]
79pub struct JigData {
80    /// When the JIG was first created.
81    pub created_at: DateTime<Utc>,
82
83    /// When the jig was last edited
84    pub last_edited: Option<DateTime<Utc>>,
85
86    /// Whether the JIG data is the live copy or the draft.
87    pub draft_or_live: DraftOrLive,
88
89    /// The JIG's name.
90    pub display_name: String,
91
92    /// The JIG's remaining modules.
93    ///
94    /// NOTE: the first module will always exist and will always be of type cover
95    pub modules: Vec<LiteModule>,
96
97    /// This jig's age ranges.
98    pub age_ranges: Vec<AgeRangeId>,
99
100    /// This jig's affiliations.
101    pub affiliations: Vec<AffiliationId>,
102
103    /// The language the jig uses.
104    ///
105    /// NOTE: in the format `en`, `eng`, `en-US`, `eng-US` or `eng-USA`. To be replaced with a struct that enforces this.
106    pub language: String,
107
108    /// The jig's categories.
109    pub categories: Vec<CategoryId>,
110
111    /// Additional resources of this JIG.
112    pub additional_resources: Vec<AdditionalResource>,
113
114    /// Description of the jig.
115    pub description: String,
116
117    /// Default player settings for this jig.
118    pub default_player_settings: JigPlayerSettings,
119
120    /// Theme for this jig, identified by `[ThemeId](module::body::ThemeId)`.
121    pub theme: ThemeId,
122
123    /// Background audio
124    pub audio_background: Option<AudioBackground>,
125
126    /// Audio effects
127    pub audio_effects: AudioEffects,
128
129    /// The privacy level on the JIG.
130    pub privacy_level: PrivacyLevel,
131
132    /// Lock this jig
133    pub locked: bool,
134
135    /// Other keywords used to searched for jigs
136    pub other_keywords: String,
137
138    /// translated keywords used to searched for jigs
139    pub translated_keywords: String,
140
141    /// translated descriptions
142    #[serde(default)]
143    pub translated_description: HashMap<String, String>,
144}
145
146/// These fields can be edited by admin and can be viewed by everyone
147#[derive(Serialize, Deserialize, Clone, Debug, Default)]
148#[serde(rename_all = "camelCase")]
149pub struct JigAdminData {
150    /// Rating for jig, weighted for jig search
151    #[serde(default)]
152    pub rating: Option<JigRating>,
153
154    /// if true does not appear in search
155    pub blocked: bool,
156
157    /// Indicates jig has been curated by admin
158    pub curated: bool,
159
160    /// Whether the resource is a premium resource
161    pub premium: bool,
162}
163
164/// These fields can be edited by admin and can be viewed by everyone
165#[derive(Serialize, Deserialize, Clone, Debug, Default)]
166#[serde(rename_all = "camelCase")]
167pub struct JigUpdateAdminDataRequest {
168    /// Rating for jig, weighted for jig search
169    #[serde(default, skip_serializing_if = "UpdateNonNullable::is_keep")]
170    pub rating: UpdateNonNullable<JigRating>,
171
172    /// if true does not appear in search
173    #[serde(default, skip_serializing_if = "UpdateNonNullable::is_keep")]
174    pub blocked: UpdateNonNullable<bool>,
175
176    /// Indicates jig has been curated by admin
177    #[serde(default, skip_serializing_if = "UpdateNonNullable::is_keep")]
178    pub curated: UpdateNonNullable<bool>,
179
180    /// Indicates jig is premium content
181    #[serde(default, skip_serializing_if = "UpdateNonNullable::is_keep")]
182    pub premium: UpdateNonNullable<bool>,
183}
184
185/// Transfer Jig from one user to another.
186#[derive(Serialize, Deserialize, Clone, Debug)]
187#[serde(rename_all = "camelCase")]
188pub struct JigAdminTransferRequest {
189    /// User Id to Transfer over from
190    pub from: UserId,
191
192    /// User Id to Transfer over to
193    pub to: UserId,
194
195    /// JIG Ids to transfer
196    pub jig_ids: Vec<JigId>,
197}
198
199make_path_parts!(JigTransferAdminPath => "/v1/jig/admin/transfer");
200
201/// Admin rating for Jig
202#[derive(Serialize, Deserialize, Debug, Clone, Copy, Eq, PartialEq)]
203#[cfg_attr(feature = "backend", derive(sqlx::Type))]
204#[serde(rename_all = "camelCase")]
205#[repr(i16)]
206pub enum JigRating {
207    #[allow(missing_docs)]
208    One = 1,
209    #[allow(missing_docs)]
210    Two = 2,
211    #[allow(missing_docs)]
212    Three = 3,
213}
214
215impl TryFrom<u8> for JigRating {
216    type Error = ();
217
218    fn try_from(num: u8) -> Result<Self, Self::Error> {
219        match num {
220            1 => Ok(Self::One),
221            2 => Ok(Self::Two),
222            3 => Ok(Self::Three),
223            _ => Err(()),
224        }
225    }
226}
227
228/// Audio for background music
229#[derive(Serialize, Deserialize, Debug, Clone, Copy, Eq, PartialEq)]
230#[cfg_attr(feature = "backend", derive(sqlx::Type))]
231#[serde(rename_all = "camelCase")]
232#[repr(i16)]
233pub enum AudioBackground {
234    #[allow(missing_docs)]
235    FunForKids = 0,
236    #[allow(missing_docs)]
237    DancingHappy = 1,
238    #[allow(missing_docs)]
239    Jigzi1 = 2,
240    #[allow(missing_docs)]
241    Jigzi2 = 3,
242    #[allow(missing_docs)]
243    Jigzi3 = 4,
244    #[allow(missing_docs)]
245    Awestruck = 5,
246    #[allow(missing_docs)]
247    BayBounce = 6,
248    #[allow(missing_docs)]
249    CalmAndReflective = 7,
250    #[allow(missing_docs)]
251    DayWithoutRain = 8,
252    #[allow(missing_docs)]
253    DestinationFreedom = 9,
254    #[allow(missing_docs)]
255    FutureMemories = 10,
256    #[allow(missing_docs)]
257    HappyInstrumental = 11,
258    #[allow(missing_docs)]
259    HappyWhistle = 12,
260    #[allow(missing_docs)]
261    KidsInstrumental = 13,
262    #[allow(missing_docs)]
263    PartyKids = 14,
264    #[allow(missing_docs)]
265    RhythmKids = 15,
266    #[allow(missing_docs)]
267    SunKissed = 16,
268
269    // legacy only background audio
270    #[allow(missing_docs)]
271    LegacyCuckooToYou = 101,
272    #[allow(missing_docs)]
273    LegacyFirstEtude = 102,
274    #[allow(missing_docs)]
275    LegacyHanerotHalalu = 103,
276    #[allow(missing_docs)]
277    LegacyIslandRomp = 104,
278    #[allow(missing_docs)]
279    LegacyJiTap = 105,
280    #[allow(missing_docs)]
281    LegacyMaozTzur = 106,
282    #[allow(missing_docs)]
283    LegacyModehAni = 107,
284    #[allow(missing_docs)]
285    LegacyMonkeyBars = 108,
286    #[allow(missing_docs)]
287    LegacyMorningZoo = 109,
288    #[allow(missing_docs)]
289    LegacyNapTime = 110,
290    #[allow(missing_docs)]
291    LegacyPlaylandMarch = 111,
292    #[allow(missing_docs)]
293    LegacyShehechiyanu = 112,
294    #[allow(missing_docs)]
295    LegacySunAndNoClouds = 113,
296    #[allow(missing_docs)]
297    LegacyTeddysBear = 114,
298    #[allow(missing_docs)]
299    LegacyWanderingWalrus = 115,
300    #[allow(missing_docs)]
301    LegacyWindupLullaby = 116,
302}
303
304impl AudioBackground {
305    /// Get all enum variants (except legacy)
306    pub fn variants() -> Vec<Self> {
307        vec![
308            Self::FunForKids,
309            Self::DancingHappy,
310            Self::Jigzi1,
311            Self::Jigzi2,
312            Self::Jigzi3,
313            Self::Awestruck,
314            Self::BayBounce,
315            Self::CalmAndReflective,
316            Self::DayWithoutRain,
317            Self::DestinationFreedom,
318            Self::FutureMemories,
319            Self::HappyInstrumental,
320            Self::HappyWhistle,
321            Self::KidsInstrumental,
322            Self::PartyKids,
323            Self::RhythmKids,
324            Self::SunKissed,
325        ]
326    }
327}
328
329/// Audio Effects
330#[derive(Serialize, Deserialize, Debug, Clone, Default)]
331#[serde(rename_all = "camelCase")]
332pub struct AudioEffects {
333    /// Positive audio feedback
334    pub feedback_positive: HashSet<AudioFeedbackPositive>,
335
336    /// Negative audio feedback
337    pub feedback_negative: HashSet<AudioFeedbackNegative>,
338}
339
340/// Negative Audio Feedback
341#[derive(Serialize, Deserialize, Debug, Clone, Copy, Eq, PartialEq, Hash)]
342#[cfg_attr(feature = "backend", derive(sqlx::Type))]
343#[serde(rename_all = "camelCase")]
344#[repr(i16)]
345pub enum AudioFeedbackNegative {
346    #[allow(missing_docs)]
347    Bang = 0,
348    #[allow(missing_docs)]
349    Boing = 1,
350    #[allow(missing_docs)]
351    Buzz = 2,
352    #[allow(missing_docs)]
353    Buzzer = 3,
354    #[allow(missing_docs)]
355    Clang = 4,
356    #[allow(missing_docs)]
357    Clicks = 5,
358    #[allow(missing_docs)]
359    Incorrect = 6,
360    #[allow(missing_docs)]
361    JumpWrong = 7,
362    #[allow(missing_docs)]
363    NotRight = 8,
364    #[allow(missing_docs)]
365    OhNo = 9,
366    #[allow(missing_docs)]
367    ShortClang = 10,
368    #[allow(missing_docs)]
369    Whir = 11,
370}
371impl AudioFeedbackNegative {
372    /// Get all enum variants
373    pub fn variants() -> Vec<AudioFeedbackNegative> {
374        vec![
375            AudioFeedbackNegative::Bang,
376            AudioFeedbackNegative::Boing,
377            AudioFeedbackNegative::Buzz,
378            AudioFeedbackNegative::Buzzer,
379            AudioFeedbackNegative::Clang,
380            AudioFeedbackNegative::Clicks,
381            AudioFeedbackNegative::Incorrect,
382            AudioFeedbackNegative::JumpWrong,
383            AudioFeedbackNegative::NotRight,
384            AudioFeedbackNegative::OhNo,
385            AudioFeedbackNegative::ShortClang,
386            AudioFeedbackNegative::Whir,
387        ]
388    }
389
390    /// Get default sounds
391    pub fn default_options() -> Vec<Self> {
392        vec![Self::Boing, Self::Buzz, Self::JumpWrong]
393    }
394}
395
396/// Positive Audio Feedback
397#[derive(Serialize, Deserialize, Debug, Clone, Copy, Eq, PartialEq, Hash)]
398#[cfg_attr(feature = "backend", derive(sqlx::Type))]
399#[serde(rename_all = "camelCase")]
400#[repr(i16)]
401pub enum AudioFeedbackPositive {
402    #[allow(missing_docs)]
403    Correct = 0,
404    #[allow(missing_docs)]
405    Keys = 1,
406    #[allow(missing_docs)]
407    Magic = 2,
408    #[allow(missing_docs)]
409    Notes = 3,
410    #[allow(missing_docs)]
411    StarPing = 4,
412    #[allow(missing_docs)]
413    Ting = 5,
414    #[allow(missing_docs)]
415    Trumpet = 6,
416    #[allow(missing_docs)]
417    VoiceAwesome = 7,
418    #[allow(missing_docs)]
419    VoicesHurray = 8,
420    #[allow(missing_docs)]
421    VoiceYippee = 9,
422    #[allow(missing_docs)]
423    Xylophone = 10,
424    #[allow(missing_docs)]
425    Yes = 11,
426}
427impl AudioFeedbackPositive {
428    /// Get all enum variants
429    pub fn variants() -> Vec<AudioFeedbackPositive> {
430        vec![
431            AudioFeedbackPositive::Correct,
432            AudioFeedbackPositive::Keys,
433            AudioFeedbackPositive::Magic,
434            AudioFeedbackPositive::Notes,
435            AudioFeedbackPositive::StarPing,
436            AudioFeedbackPositive::Ting,
437            AudioFeedbackPositive::Trumpet,
438            AudioFeedbackPositive::VoiceAwesome,
439            AudioFeedbackPositive::VoicesHurray,
440            AudioFeedbackPositive::VoiceYippee,
441            AudioFeedbackPositive::Xylophone,
442            AudioFeedbackPositive::Yes,
443        ]
444    }
445
446    /// Get default sounds
447    pub fn default_options() -> Vec<Self> {
448        vec![Self::VoiceYippee, Self::Xylophone]
449    }
450}
451
452/// The response returned when a request for `GET`ing a jig is successful.
453#[derive(Serialize, Deserialize, Debug, Clone)]
454#[serde(rename_all = "camelCase")]
455pub struct JigResponse {
456    /// The ID of the JIG.
457    pub id: JigId,
458
459    /// When (if at all) the JIG has published a draft to live.
460    pub published_at: Option<DateTime<Utc>>,
461
462    /// The ID of the JIG's original creator ([`None`] if unknown).
463    pub creator_id: Option<UserId>,
464
465    /// The current author
466    pub author_id: Option<UserId>,
467
468    /// The author's name, as "{given_name} {family_name}".
469    pub author_name: Option<String>,
470
471    /// Number of likes on Jig
472    pub likes: i64,
473
474    /// Number of plays Jig
475    pub plays: i64,
476
477    /// Live is current to Draft
478    pub live_up_to_date: bool,
479
480    /// The data of the requested JIG.
481    pub jig_data: JigData,
482
483    /// Liked by current user.
484    pub is_liked: bool,
485
486    /// Admin data for Jig
487    pub admin_data: JigAdminData,
488}
489
490make_path_parts!(JigGetLivePath => "/v1/jig/{}/live" => JigId);
491
492make_path_parts!(JigGetDraftPath => "/v1/jig/{}/draft" => JigId);
493
494make_path_parts!(JigUpdateDraftDataPath => "/v1/jig/{}" => JigId);
495
496/// Request for updating a JIG's draft data.
497#[derive(Serialize, Deserialize, Debug, Default)]
498#[serde(rename_all = "camelCase")]
499pub struct JigUpdateDraftDataRequest {
500    /// The JIG's name.
501    #[serde(skip_serializing_if = "Option::is_none")]
502    #[serde(default)]
503    pub display_name: Option<String>,
504
505    /// The language the jig uses.
506    ///
507    /// NOTE: in the format `en`, `eng`, `en-US`, `eng-US` or `eng-USA`. To be replaced with a struct that enforces this.
508    #[serde(skip_serializing_if = "Option::is_none")]
509    #[serde(default)]
510    pub language: Option<String>,
511
512    /// The jig's categories.
513    #[serde(skip_serializing_if = "Option::is_none")]
514    #[serde(default)]
515    pub categories: Option<Vec<CategoryId>>,
516
517    /// The jig's age ranges.
518    #[serde(skip_serializing_if = "Option::is_none")]
519    #[serde(default)]
520    pub age_ranges: Option<Vec<AgeRangeId>>,
521
522    /// The jig's affiliations.
523    #[serde(skip_serializing_if = "Option::is_none")]
524    #[serde(default)]
525    pub affiliations: Option<Vec<AffiliationId>>,
526
527    /// The current author
528    #[serde(skip_serializing_if = "Option::is_none")]
529    #[serde(default)]
530    pub author_id: Option<UserId>,
531
532    /// Description of the jig.
533    #[serde(skip_serializing_if = "Option::is_none")]
534    #[serde(default)]
535    pub description: Option<String>,
536
537    /// Default player settings for this jig.
538    #[serde(skip_serializing_if = "Option::is_none")]
539    #[serde(default)]
540    pub default_player_settings: Option<JigPlayerSettings>,
541
542    /// Theme for this jig, identified by `[ThemeId](module::body::ThemeId)`.
543    #[serde(skip_serializing_if = "Option::is_none")]
544    #[serde(default)]
545    pub theme: Option<ThemeId>,
546
547    /// Background audio
548    #[serde(deserialize_with = "super::deserialize_optional_field")]
549    #[serde(skip_serializing_if = "Option::is_none")]
550    #[serde(default)]
551    pub audio_background: Option<Option<AudioBackground>>,
552
553    /// Audio effects
554    #[serde(skip_serializing_if = "Option::is_none")]
555    #[serde(default)]
556    pub audio_effects: Option<AudioEffects>,
557
558    /// Privacy level for the jig.
559    #[serde(skip_serializing_if = "Option::is_none")]
560    #[serde(default)]
561    pub privacy_level: Option<PrivacyLevel>,
562
563    /// Additional keywords for searches
564    #[serde(skip_serializing_if = "Option::is_none")]
565    #[serde(default)]
566    pub other_keywords: Option<String>,
567}
568
569make_path_parts!(JigPublishPath => "/v1/jig/{}/draft/publish" => JigId);
570
571make_path_parts!(JigBrowsePath => "/v1/jig/browse");
572
573/// Query for [`Browse`](crate::api::endpoints::jig::Browse).
574#[derive(Serialize, Deserialize, Clone, Debug, Default)]
575#[serde(rename_all = "camelCase")]
576pub struct JigBrowseQuery {
577    /// Optionally filter by `is_published`
578    #[serde(default)]
579    #[serde(skip_serializing_if = "Option::is_none")]
580    pub is_published: Option<bool>,
581
582    /// Optionally filter by author id.
583    #[serde(default)]
584    #[serde(skip_serializing_if = "Option::is_none")]
585    pub author_id: Option<UserOrMe>,
586
587    /// The page number of the jigs to get.
588    #[serde(default)]
589    #[serde(skip_serializing_if = "Option::is_none")]
590    pub page: Option<u32>,
591
592    /// Optionally browse by draft or live.
593    #[serde(default)]
594    #[serde(skip_serializing_if = "Option::is_none")]
595    pub draft_or_live: Option<DraftOrLive>,
596
597    /// Optionally filter jig by their privacy level
598    #[serde(default)]
599    #[serde(deserialize_with = "super::from_csv")]
600    #[serde(skip_serializing_if = "Vec::is_empty")]
601    pub privacy_level: Vec<PrivacyLevel>,
602
603    /// Optionally filter jig by blocked status
604    #[serde(default)]
605    #[serde(skip_serializing_if = "Option::is_none")]
606    pub blocked: Option<bool>,
607
608    /// The hits per page to be returned
609    #[serde(default)]
610    #[serde(skip_serializing_if = "Option::is_none")]
611    pub page_limit: Option<u32>,
612
613    /// Optionally filter by `additional resources`
614    #[serde(default)]
615    #[serde(serialize_with = "super::csv_encode_uuids")]
616    #[serde(deserialize_with = "super::from_csv")]
617    #[serde(skip_serializing_if = "Vec::is_empty")]
618    pub resource_types: Vec<ResourceTypeId>,
619
620    /// The hits per page to be returned
621    #[serde(default)]
622    #[serde(skip_serializing_if = "Option::is_none")]
623    pub order_by: Option<OrderBy>,
624}
625
626/// Response for [`Browse`](crate::api::endpoints::jig::Browse).
627#[derive(Serialize, Deserialize, Clone, Debug)]
628#[serde(rename_all = "camelCase")]
629pub struct JigBrowseResponse {
630    /// the jigs returned.
631    pub jigs: Vec<JigResponse>,
632
633    /// The number of pages found.
634    pub pages: u32,
635
636    /// The total number of jigs found
637    pub total_jig_count: u64,
638}
639
640make_path_parts!(JigSearchPath => "/v1/jig");
641
642/// Search for jigs via the given query string.
643#[derive(Serialize, Deserialize, Clone, Debug, Default)]
644#[serde(rename_all = "camelCase")]
645pub struct JigSearchQuery {
646    /// The query string.
647    #[serde(default)]
648    #[serde(skip_serializing_if = "String::is_empty")]
649    pub q: String,
650
651    /// The page number of the jigs to get.
652    #[serde(default)]
653    #[serde(skip_serializing_if = "Option::is_none")]
654    pub page: Option<u32>,
655
656    /// Optionally filter by `language`
657    #[serde(default)]
658    #[serde(skip_serializing_if = "Option::is_none")]
659    pub language: Option<String>,
660
661    /// Optionally filter by `age_ranges`
662    ///
663    /// Note: Currently does nothing
664    #[serde(default)]
665    #[serde(serialize_with = "super::csv_encode_uuids")]
666    #[serde(deserialize_with = "super::from_csv")]
667    #[serde(skip_serializing_if = "Vec::is_empty")]
668    pub age_ranges: Vec<AgeRangeId>,
669
670    /// Optionally filter by `affiliations`
671    ///
672    /// Note: Currently does nothing
673    #[serde(default)]
674    #[serde(serialize_with = "super::csv_encode_uuids")]
675    #[serde(deserialize_with = "super::from_csv")]
676    #[serde(skip_serializing_if = "Vec::is_empty")]
677    pub affiliations: Vec<AffiliationId>,
678
679    /// Optionally filter by `additional resources`
680    #[serde(default)]
681    #[serde(serialize_with = "super::csv_encode_uuids")]
682    #[serde(deserialize_with = "super::from_csv")]
683    #[serde(skip_serializing_if = "Vec::is_empty")]
684    pub resource_types: Vec<ResourceTypeId>,
685
686    /// Optionally filter by `categories`
687    #[serde(default)]
688    #[serde(serialize_with = "super::csv_encode_uuids")]
689    #[serde(deserialize_with = "super::from_csv")]
690    #[serde(skip_serializing_if = "Vec::is_empty")]
691    pub categories: Vec<CategoryId>,
692
693    /// Optionally filter by `is_published`. This means that the jig's `publish_at < now()`.
694    #[serde(default)]
695    #[serde(skip_serializing_if = "Option::is_none")]
696    pub is_published: Option<bool>,
697
698    /// Optionally filter by author's id
699    #[serde(default)]
700    #[serde(skip_serializing_if = "Option::is_none")]
701    pub author_id: Option<UserOrMe>,
702
703    /// Optionally filter by the author's name
704    #[serde(default)]
705    #[serde(skip_serializing_if = "Option::is_none")]
706    pub author_name: Option<String>,
707
708    /// Optionally search for jigs using keywords
709    #[serde(default)]
710    #[serde(skip_serializing_if = "Option::is_none")]
711    pub other_keywords: Option<String>,
712
713    /// Optionally search for jigs using translated keyword
714    #[serde(default)]
715    #[serde(skip_serializing_if = "Option::is_none")]
716    pub translated_keywords: Option<String>,
717
718    /// Optionally search for jigs by privacy level
719    #[serde(default)]
720    #[serde(deserialize_with = "super::from_csv")]
721    #[serde(skip_serializing_if = "Vec::is_empty")]
722    pub privacy_level: Vec<PrivacyLevel>,
723
724    /// Optionally search for blocked or non-blocked jigs
725    #[serde(default)]
726    #[serde(skip_serializing_if = "Option::is_none")]
727    pub blocked: Option<bool>,
728
729    /// The hits per page to be returned
730    #[serde(default)]
731    #[serde(skip_serializing_if = "Option::is_none")]
732    pub page_limit: Option<u32>,
733
734    /// Optionally filter JIGs based off of existence of rating
735    #[serde(default)]
736    #[serde(skip_serializing_if = "Option::is_none")]
737    pub is_rated: Option<bool>,
738}
739
740/// Response for successful search.
741#[derive(Serialize, Deserialize, Clone, Debug)]
742#[serde(rename_all = "camelCase")]
743pub struct JigSearchResponse {
744    /// the jigs returned.
745    pub jigs: Vec<JigResponse>,
746
747    /// The number of pages found.
748    pub pages: u32,
749
750    /// The total number of jigs found
751    pub total_jig_count: u64,
752}
753
754make_path_parts!(JigTrendingPath => "/v1/jig/trending");
755
756/// Response for request for trending.
757#[derive(Serialize, Deserialize, Clone, Debug)]
758#[serde(rename_all = "camelCase")]
759pub struct JigTrendingResponse {
760    /// the jigs returned.
761    pub jigs: Vec<JigResponse>,
762}
763
764make_path_parts!(ListLikedPath => "/v1/jig/likes");
765
766/// Response for request for list of liked jigs.
767#[derive(Serialize, Deserialize, Clone, Debug, Default)]
768#[serde(rename_all = "camelCase")]
769pub struct ListLikedRequest {
770    /// The page number of the jigs to get.
771    #[serde(default)]
772    #[serde(skip_serializing_if = "Option::is_none")]
773    pub page: Option<u32>,
774
775    /// The hits per page to be returned
776    #[serde(default)]
777    #[serde(skip_serializing_if = "Option::is_none")]
778    pub page_limit: Option<u32>,
779}
780
781make_path_parts!(ListPlayedPath => "/v1/jig/played");
782
783/// Response for request for list of played jigs.
784#[derive(Serialize, Deserialize, Clone, Debug, Default)]
785#[serde(rename_all = "camelCase")]
786pub struct ListPlayedRequest {
787    /// The page number of the jigs to get.
788    #[serde(default)]
789    #[serde(skip_serializing_if = "Option::is_none")]
790    pub page: Option<u32>,
791
792    /// The hits per page to be returned
793    #[serde(default)]
794    #[serde(skip_serializing_if = "Option::is_none")]
795    pub page_limit: Option<u32>,
796}
797
798/// Response for request for list of played jigs.
799#[derive(Serialize, Deserialize, Clone, Debug)]
800#[serde(rename_all = "camelCase")]
801pub struct ListPlayedResponse {
802    /// the jigs returned.
803    pub jigs: Vec<JigResponse>,
804}
805
806make_path_parts!(JigFeaturedPath => "/v1/jig/featured");
807
808/// Response for request for featured.
809#[derive(Serialize, Deserialize, Clone, Debug)]
810#[serde(rename_all = "camelCase")]
811pub struct JigFeaturedResponse {
812    /// the jigs returned.
813    pub jigs: Vec<JigResponse>,
814}
815
816/// Request for request for featured.
817#[derive(Serialize, Deserialize, Clone, Debug)]
818#[serde(rename_all = "camelCase")]
819pub struct JigFeaturedUpdateRequest {
820    /// the jigs to feature.
821    pub jigs: Vec<JigId>,
822}
823
824/// Response for request for list of liked jigs.
825#[derive(Serialize, Deserialize, Clone, Debug)]
826#[serde(rename_all = "camelCase")]
827pub struct ListLikedResponse {
828    /// the jigs returned.
829    pub jigs: Vec<JigResponse>,
830
831    /// The total number of jigs liked
832    pub total_jig_count: u64,
833}
834
835/// Response for successfully finding the draft of a jig.
836#[derive(Serialize, Deserialize, Clone, Debug)]
837#[serde(rename_all = "camelCase")]
838pub struct JigIdResponse {
839    /// The ID of the jig
840    pub id: JigId,
841}
842
843make_path_parts!(JigClonePath => "/v1/jig/{}/clone" => JigId);
844
845make_path_parts!(JigDeletePath => "/v1/jig/{}" => JigId);
846
847make_path_parts!(JigDeleteAllPath => "/v1/jig");
848
849make_path_parts!(JigCoverPath => "/v1/jig/{}/cover" => JigId);
850
851make_path_parts!(JigCountPath => "/v1/jig/count");
852
853/// Response for total count of public and published jig.
854#[derive(Serialize, Deserialize, Clone, Debug)]
855#[serde(rename_all = "camelCase")]
856pub struct JigCountResponse {
857    /// Total number of public and published jigs.
858    pub total_count: u64,
859}
860
861make_path_parts!(JigLikePath => "/v1/jig/{}/like" => JigId);
862
863make_path_parts!(JigUnlikePath => "/v1/jig/{}/unlike" => JigId);
864
865make_path_parts!(JigLikedPath => "/v1/jig/{}/like" => JigId);
866
867/// Response for whether a user has liked a JIG.
868#[derive(Serialize, Deserialize, Clone, Debug)]
869pub struct JigLikedResponse {
870    /// Whether the authenticated user has liked the current JIG
871    pub is_liked: bool,
872}
873
874make_path_parts!(JigPlayPath => "/v1/jig/{}/play" => JigId);
875
876make_path_parts!(JigAdminDataUpdatePath => "/v1/jig/{}/admin" => JigId);
877
878/// Response list of Playlists that JIG is associated with.
879#[derive(Serialize, Deserialize, Clone, Debug)]
880#[serde(rename_all = "camelCase")]
881pub struct GetJigPlaylistsResponse {
882    /// the jigs returned.
883    pub playlists: Vec<PlaylistResponse>,
884}
885
886macros::make_path_parts!(GetJigPlaylistsPath => "/v1/jig/{}/playlists" => JigId);
887
888/// A jigs export representation.
889#[derive(Debug, Serialize, Deserialize, Clone)]
890pub struct AdminJigExport {
891    /// JIG ID
892    pub id: JigId,
893    /// Description of the jig.
894    pub description: String,
895    /// The JIG's name.
896    pub display_name: String,
897    /// Whether the resource is a premium resource
898    pub premium: bool,
899    /// if true does not appear in search
900    pub blocked: bool,
901    /// The current author
902    pub author_id: Option<UserId>,
903    /// The author's name, as "{given_name} {family_name}".
904    pub author_name: Option<String>,
905    /// Number of likes on Jig
906    pub likes: i64,
907    /// Number of plays Jig
908    pub plays: i64,
909    /// Rating for jig, weighted for jig search
910    pub rating: Option<JigRating>,
911    /// The privacy level on the JIG.
912    pub privacy_level: PrivacyLevel,
913    /// When the JIG was first created.
914    pub created_at: DateTime<Utc>,
915    /// When (if at all) the JIG has published a draft to live.
916    pub published_at: Option<DateTime<Utc>>,
917    /// The language the jig uses.
918    pub language: String,
919}