pub mod curation;
pub mod report;
use macros::make_path_parts;
pub use report::{JigReport, ReportId};
pub mod codes;
pub mod player;
pub use player::{JigPlayerSettings, TextDirection};
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use std::collections::{HashMap, HashSet};
use super::{
additional_resource::AdditionalResource,
asset::{DraftOrLive, OrderBy, PrivacyLevel, UserOrMe},
category::CategoryId,
meta::{AffiliationId, AgeRangeId, ResourceTypeId},
module::LiteModule,
playlist::PlaylistResponse,
user::UserId,
};
use crate::domain::UpdateNonNullable;
use crate::{api::endpoints::PathPart, domain::module::body::ThemeId};
wrap_uuid! {
pub struct JigId
}
make_path_parts!(JigCreatePath => "/v1/jig");
#[derive(Serialize, Deserialize, Debug, Default)]
#[serde(rename_all = "camelCase")]
pub struct JigCreateRequest {
#[serde(default)]
pub display_name: String,
#[serde(skip_serializing_if = "Vec::is_empty")]
#[serde(default)]
pub age_ranges: Vec<AgeRangeId>,
#[serde(skip_serializing_if = "Vec::is_empty")]
#[serde(default)]
pub affiliations: Vec<AffiliationId>,
#[serde(default)]
pub language: String,
#[serde(skip_serializing_if = "Vec::is_empty")]
#[serde(default)]
pub categories: Vec<CategoryId>,
#[serde(default)]
pub description: String,
#[serde(default)]
pub default_player_settings: JigPlayerSettings,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
#[serde(rename_all = "camelCase")]
pub struct JigData {
pub created_at: DateTime<Utc>,
pub last_edited: Option<DateTime<Utc>>,
pub draft_or_live: DraftOrLive,
pub display_name: String,
pub modules: Vec<LiteModule>,
pub age_ranges: Vec<AgeRangeId>,
pub affiliations: Vec<AffiliationId>,
pub language: String,
pub categories: Vec<CategoryId>,
pub additional_resources: Vec<AdditionalResource>,
pub description: String,
pub default_player_settings: JigPlayerSettings,
pub theme: ThemeId,
pub audio_background: Option<AudioBackground>,
pub audio_effects: AudioEffects,
pub privacy_level: PrivacyLevel,
pub locked: bool,
pub other_keywords: String,
pub translated_keywords: String,
#[serde(default)]
pub translated_description: HashMap<String, String>,
}
#[derive(Serialize, Deserialize, Clone, Debug, Default)]
#[serde(rename_all = "camelCase")]
pub struct JigAdminData {
#[serde(default)]
pub rating: Option<JigRating>,
pub blocked: bool,
pub curated: bool,
pub premium: bool,
}
#[derive(Serialize, Deserialize, Clone, Debug, Default)]
#[serde(rename_all = "camelCase")]
pub struct JigUpdateAdminDataRequest {
#[serde(default, skip_serializing_if = "UpdateNonNullable::is_keep")]
pub rating: UpdateNonNullable<JigRating>,
#[serde(default, skip_serializing_if = "UpdateNonNullable::is_keep")]
pub blocked: UpdateNonNullable<bool>,
#[serde(default, skip_serializing_if = "UpdateNonNullable::is_keep")]
pub curated: UpdateNonNullable<bool>,
#[serde(default, skip_serializing_if = "UpdateNonNullable::is_keep")]
pub premium: UpdateNonNullable<bool>,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
#[serde(rename_all = "camelCase")]
pub struct JigAdminTransferRequest {
pub from: UserId,
pub to: UserId,
pub jig_ids: Vec<JigId>,
}
make_path_parts!(JigTransferAdminPath => "/v1/jig/admin/transfer");
#[derive(Serialize, Deserialize, Debug, Clone, Copy, Eq, PartialEq)]
#[cfg_attr(feature = "backend", derive(sqlx::Type))]
#[serde(rename_all = "camelCase")]
#[repr(i16)]
pub enum JigRating {
#[allow(missing_docs)]
One = 1,
#[allow(missing_docs)]
Two = 2,
#[allow(missing_docs)]
Three = 3,
}
impl TryFrom<u8> for JigRating {
type Error = ();
fn try_from(num: u8) -> Result<Self, Self::Error> {
match num {
1 => Ok(Self::One),
2 => Ok(Self::Two),
3 => Ok(Self::Three),
_ => Err(()),
}
}
}
#[derive(Serialize, Deserialize, Debug, Clone, Copy, Eq, PartialEq)]
#[cfg_attr(feature = "backend", derive(sqlx::Type))]
#[serde(rename_all = "camelCase")]
#[repr(i16)]
pub enum AudioBackground {
#[allow(missing_docs)]
FunForKids = 0,
#[allow(missing_docs)]
DancingHappy = 1,
#[allow(missing_docs)]
Jigzi1 = 2,
#[allow(missing_docs)]
Jigzi2 = 3,
#[allow(missing_docs)]
Jigzi3 = 4,
#[allow(missing_docs)]
Awestruck = 5,
#[allow(missing_docs)]
BayBounce = 6,
#[allow(missing_docs)]
CalmAndReflective = 7,
#[allow(missing_docs)]
DayWithoutRain = 8,
#[allow(missing_docs)]
DestinationFreedom = 9,
#[allow(missing_docs)]
FutureMemories = 10,
#[allow(missing_docs)]
HappyInstrumental = 11,
#[allow(missing_docs)]
HappyWhistle = 12,
#[allow(missing_docs)]
KidsInstrumental = 13,
#[allow(missing_docs)]
PartyKids = 14,
#[allow(missing_docs)]
RhythmKids = 15,
#[allow(missing_docs)]
SunKissed = 16,
#[allow(missing_docs)]
LegacyCuckooToYou = 101,
#[allow(missing_docs)]
LegacyFirstEtude = 102,
#[allow(missing_docs)]
LegacyHanerotHalalu = 103,
#[allow(missing_docs)]
LegacyIslandRomp = 104,
#[allow(missing_docs)]
LegacyJiTap = 105,
#[allow(missing_docs)]
LegacyMaozTzur = 106,
#[allow(missing_docs)]
LegacyModehAni = 107,
#[allow(missing_docs)]
LegacyMonkeyBars = 108,
#[allow(missing_docs)]
LegacyMorningZoo = 109,
#[allow(missing_docs)]
LegacyNapTime = 110,
#[allow(missing_docs)]
LegacyPlaylandMarch = 111,
#[allow(missing_docs)]
LegacyShehechiyanu = 112,
#[allow(missing_docs)]
LegacySunAndNoClouds = 113,
#[allow(missing_docs)]
LegacyTeddysBear = 114,
#[allow(missing_docs)]
LegacyWanderingWalrus = 115,
#[allow(missing_docs)]
LegacyWindupLullaby = 116,
}
impl AudioBackground {
pub fn variants() -> Vec<Self> {
vec![
Self::FunForKids,
Self::DancingHappy,
Self::Jigzi1,
Self::Jigzi2,
Self::Jigzi3,
Self::Awestruck,
Self::BayBounce,
Self::CalmAndReflective,
Self::DayWithoutRain,
Self::DestinationFreedom,
Self::FutureMemories,
Self::HappyInstrumental,
Self::HappyWhistle,
Self::KidsInstrumental,
Self::PartyKids,
Self::RhythmKids,
Self::SunKissed,
]
}
}
#[derive(Serialize, Deserialize, Debug, Clone, Default)]
#[serde(rename_all = "camelCase")]
pub struct AudioEffects {
pub feedback_positive: HashSet<AudioFeedbackPositive>,
pub feedback_negative: HashSet<AudioFeedbackNegative>,
}
#[derive(Serialize, Deserialize, Debug, Clone, Copy, Eq, PartialEq, Hash)]
#[cfg_attr(feature = "backend", derive(sqlx::Type))]
#[serde(rename_all = "camelCase")]
#[repr(i16)]
pub enum AudioFeedbackNegative {
#[allow(missing_docs)]
Bang = 0,
#[allow(missing_docs)]
Boing = 1,
#[allow(missing_docs)]
Buzz = 2,
#[allow(missing_docs)]
Buzzer = 3,
#[allow(missing_docs)]
Clang = 4,
#[allow(missing_docs)]
Clicks = 5,
#[allow(missing_docs)]
Incorrect = 6,
#[allow(missing_docs)]
JumpWrong = 7,
#[allow(missing_docs)]
NotRight = 8,
#[allow(missing_docs)]
OhNo = 9,
#[allow(missing_docs)]
ShortClang = 10,
#[allow(missing_docs)]
Whir = 11,
}
impl AudioFeedbackNegative {
pub fn variants() -> Vec<AudioFeedbackNegative> {
vec![
AudioFeedbackNegative::Bang,
AudioFeedbackNegative::Boing,
AudioFeedbackNegative::Buzz,
AudioFeedbackNegative::Buzzer,
AudioFeedbackNegative::Clang,
AudioFeedbackNegative::Clicks,
AudioFeedbackNegative::Incorrect,
AudioFeedbackNegative::JumpWrong,
AudioFeedbackNegative::NotRight,
AudioFeedbackNegative::OhNo,
AudioFeedbackNegative::ShortClang,
AudioFeedbackNegative::Whir,
]
}
pub fn default_options() -> Vec<Self> {
vec![Self::Boing, Self::Buzz, Self::JumpWrong]
}
}
#[derive(Serialize, Deserialize, Debug, Clone, Copy, Eq, PartialEq, Hash)]
#[cfg_attr(feature = "backend", derive(sqlx::Type))]
#[serde(rename_all = "camelCase")]
#[repr(i16)]
pub enum AudioFeedbackPositive {
#[allow(missing_docs)]
Correct = 0,
#[allow(missing_docs)]
Keys = 1,
#[allow(missing_docs)]
Magic = 2,
#[allow(missing_docs)]
Notes = 3,
#[allow(missing_docs)]
StarPing = 4,
#[allow(missing_docs)]
Ting = 5,
#[allow(missing_docs)]
Trumpet = 6,
#[allow(missing_docs)]
VoiceAwesome = 7,
#[allow(missing_docs)]
VoicesHurray = 8,
#[allow(missing_docs)]
VoiceYippee = 9,
#[allow(missing_docs)]
Xylophone = 10,
#[allow(missing_docs)]
Yes = 11,
}
impl AudioFeedbackPositive {
pub fn variants() -> Vec<AudioFeedbackPositive> {
vec![
AudioFeedbackPositive::Correct,
AudioFeedbackPositive::Keys,
AudioFeedbackPositive::Magic,
AudioFeedbackPositive::Notes,
AudioFeedbackPositive::StarPing,
AudioFeedbackPositive::Ting,
AudioFeedbackPositive::Trumpet,
AudioFeedbackPositive::VoiceAwesome,
AudioFeedbackPositive::VoicesHurray,
AudioFeedbackPositive::VoiceYippee,
AudioFeedbackPositive::Xylophone,
AudioFeedbackPositive::Yes,
]
}
pub fn default_options() -> Vec<Self> {
vec![Self::VoiceYippee, Self::Xylophone]
}
}
#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(rename_all = "camelCase")]
pub struct JigResponse {
pub id: JigId,
pub published_at: Option<DateTime<Utc>>,
pub creator_id: Option<UserId>,
pub author_id: Option<UserId>,
pub author_name: Option<String>,
pub likes: i64,
pub plays: i64,
pub live_up_to_date: bool,
pub jig_data: JigData,
pub is_liked: bool,
pub admin_data: JigAdminData,
}
make_path_parts!(JigGetLivePath => "/v1/jig/{}/live" => JigId);
make_path_parts!(JigGetDraftPath => "/v1/jig/{}/draft" => JigId);
make_path_parts!(JigUpdateDraftDataPath => "/v1/jig/{}" => JigId);
#[derive(Serialize, Deserialize, Debug, Default)]
#[serde(rename_all = "camelCase")]
pub struct JigUpdateDraftDataRequest {
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(default)]
pub display_name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(default)]
pub language: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(default)]
pub categories: Option<Vec<CategoryId>>,
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(default)]
pub age_ranges: Option<Vec<AgeRangeId>>,
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(default)]
pub affiliations: Option<Vec<AffiliationId>>,
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(default)]
pub author_id: Option<UserId>,
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(default)]
pub description: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(default)]
pub default_player_settings: Option<JigPlayerSettings>,
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(default)]
pub theme: Option<ThemeId>,
#[serde(deserialize_with = "super::deserialize_optional_field")]
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(default)]
pub audio_background: Option<Option<AudioBackground>>,
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(default)]
pub audio_effects: Option<AudioEffects>,
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(default)]
pub privacy_level: Option<PrivacyLevel>,
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(default)]
pub other_keywords: Option<String>,
}
make_path_parts!(JigPublishPath => "/v1/jig/{}/draft/publish" => JigId);
make_path_parts!(JigBrowsePath => "/v1/jig/browse");
#[derive(Serialize, Deserialize, Clone, Debug, Default)]
#[serde(rename_all = "camelCase")]
pub struct JigBrowseQuery {
#[serde(default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub is_published: Option<bool>,
#[serde(default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub author_id: Option<UserOrMe>,
#[serde(default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub page: Option<u32>,
#[serde(default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub draft_or_live: Option<DraftOrLive>,
#[serde(default)]
#[serde(deserialize_with = "super::from_csv")]
#[serde(skip_serializing_if = "Vec::is_empty")]
pub privacy_level: Vec<PrivacyLevel>,
#[serde(default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub blocked: Option<bool>,
#[serde(default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub page_limit: Option<u32>,
#[serde(default)]
#[serde(serialize_with = "super::csv_encode_uuids")]
#[serde(deserialize_with = "super::from_csv")]
#[serde(skip_serializing_if = "Vec::is_empty")]
pub resource_types: Vec<ResourceTypeId>,
#[serde(default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub order_by: Option<OrderBy>,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
#[serde(rename_all = "camelCase")]
pub struct JigBrowseResponse {
pub jigs: Vec<JigResponse>,
pub pages: u32,
pub total_jig_count: u64,
}
make_path_parts!(JigSearchPath => "/v1/jig");
#[derive(Serialize, Deserialize, Clone, Debug, Default)]
#[serde(rename_all = "camelCase")]
pub struct JigSearchQuery {
#[serde(default)]
#[serde(skip_serializing_if = "String::is_empty")]
pub q: String,
#[serde(default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub page: Option<u32>,
#[serde(default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub language: Option<String>,
#[serde(default)]
#[serde(serialize_with = "super::csv_encode_uuids")]
#[serde(deserialize_with = "super::from_csv")]
#[serde(skip_serializing_if = "Vec::is_empty")]
pub age_ranges: Vec<AgeRangeId>,
#[serde(default)]
#[serde(serialize_with = "super::csv_encode_uuids")]
#[serde(deserialize_with = "super::from_csv")]
#[serde(skip_serializing_if = "Vec::is_empty")]
pub affiliations: Vec<AffiliationId>,
#[serde(default)]
#[serde(serialize_with = "super::csv_encode_uuids")]
#[serde(deserialize_with = "super::from_csv")]
#[serde(skip_serializing_if = "Vec::is_empty")]
pub resource_types: Vec<ResourceTypeId>,
#[serde(default)]
#[serde(serialize_with = "super::csv_encode_uuids")]
#[serde(deserialize_with = "super::from_csv")]
#[serde(skip_serializing_if = "Vec::is_empty")]
pub categories: Vec<CategoryId>,
#[serde(default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub is_published: Option<bool>,
#[serde(default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub author_id: Option<UserOrMe>,
#[serde(default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub author_name: Option<String>,
#[serde(default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub other_keywords: Option<String>,
#[serde(default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub translated_keywords: Option<String>,
#[serde(default)]
#[serde(deserialize_with = "super::from_csv")]
#[serde(skip_serializing_if = "Vec::is_empty")]
pub privacy_level: Vec<PrivacyLevel>,
#[serde(default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub blocked: Option<bool>,
#[serde(default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub page_limit: Option<u32>,
#[serde(default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub is_rated: Option<bool>,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
#[serde(rename_all = "camelCase")]
pub struct JigSearchResponse {
pub jigs: Vec<JigResponse>,
pub pages: u32,
pub total_jig_count: u64,
}
make_path_parts!(JigTrendingPath => "/v1/jig/trending");
#[derive(Serialize, Deserialize, Clone, Debug)]
#[serde(rename_all = "camelCase")]
pub struct JigTrendingResponse {
pub jigs: Vec<JigResponse>,
}
make_path_parts!(ListLikedPath => "/v1/jig/likes");
#[derive(Serialize, Deserialize, Clone, Debug, Default)]
#[serde(rename_all = "camelCase")]
pub struct ListLikedRequest {
#[serde(default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub page: Option<u32>,
#[serde(default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub page_limit: Option<u32>,
}
make_path_parts!(ListPlayedPath => "/v1/jig/played");
#[derive(Serialize, Deserialize, Clone, Debug, Default)]
#[serde(rename_all = "camelCase")]
pub struct ListPlayedRequest {
#[serde(default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub page: Option<u32>,
#[serde(default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub page_limit: Option<u32>,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
#[serde(rename_all = "camelCase")]
pub struct ListPlayedResponse {
pub jigs: Vec<JigResponse>,
}
make_path_parts!(JigFeaturedPath => "/v1/jig/featured");
#[derive(Serialize, Deserialize, Clone, Debug)]
#[serde(rename_all = "camelCase")]
pub struct JigFeaturedResponse {
pub jigs: Vec<JigResponse>,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
#[serde(rename_all = "camelCase")]
pub struct JigFeaturedUpdateRequest {
pub jigs: Vec<JigId>,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
#[serde(rename_all = "camelCase")]
pub struct ListLikedResponse {
pub jigs: Vec<JigResponse>,
pub total_jig_count: u64,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
#[serde(rename_all = "camelCase")]
pub struct JigIdResponse {
pub id: JigId,
}
make_path_parts!(JigClonePath => "/v1/jig/{}/clone" => JigId);
make_path_parts!(JigDeletePath => "/v1/jig/{}" => JigId);
make_path_parts!(JigDeleteAllPath => "/v1/jig");
make_path_parts!(JigCoverPath => "/v1/jig/{}/cover" => JigId);
make_path_parts!(JigCountPath => "/v1/jig/count");
#[derive(Serialize, Deserialize, Clone, Debug)]
#[serde(rename_all = "camelCase")]
pub struct JigCountResponse {
pub total_count: u64,
}
make_path_parts!(JigLikePath => "/v1/jig/{}/like" => JigId);
make_path_parts!(JigUnlikePath => "/v1/jig/{}/unlike" => JigId);
make_path_parts!(JigLikedPath => "/v1/jig/{}/like" => JigId);
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct JigLikedResponse {
pub is_liked: bool,
}
make_path_parts!(JigPlayPath => "/v1/jig/{}/play" => JigId);
make_path_parts!(JigAdminDataUpdatePath => "/v1/jig/{}/admin" => JigId);
#[derive(Serialize, Deserialize, Clone, Debug)]
#[serde(rename_all = "camelCase")]
pub struct GetJigPlaylistsResponse {
pub playlists: Vec<PlaylistResponse>,
}
macros::make_path_parts!(GetJigPlaylistsPath => "/v1/jig/{}/playlists" => JigId);
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct AdminJigExport {
pub id: JigId,
pub description: String,
pub display_name: String,
pub premium: bool,
pub blocked: bool,
pub author_id: Option<UserId>,
pub author_name: Option<String>,
pub likes: i64,
pub plays: i64,
pub rating: Option<JigRating>,
pub privacy_level: PrivacyLevel,
pub created_at: DateTime<Utc>,
pub published_at: Option<DateTime<Utc>>,
pub language: String,
}