use crate::domain::UpdateNonNullable;
use chrono::{DateTime, Utc};
use macros::make_path_parts;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use super::{
super::api::endpoints::PathPart,
additional_resource::AdditionalResource,
asset::{DraftOrLive, PrivacyLevel, UserOrMe},
category::CategoryId,
jig::JigId,
meta::{AffiliationId, AgeRangeId, ResourceTypeId},
module::LiteModule,
user::UserId,
};
wrap_uuid! {
pub struct PlaylistId
}
make_path_parts!(PlaylistCreatePath => "/v1/playlist");
#[derive(Serialize, Deserialize, Debug, Default)]
#[serde(rename_all = "camelCase")]
pub struct PlaylistCreateRequest {
#[serde(default)]
pub display_name: String,
#[serde(default)]
pub description: 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>,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
#[serde(rename_all = "camelCase")]
pub struct PlaylistData {
pub draft_or_live: DraftOrLive,
pub display_name: String,
pub language: String,
pub description: String,
pub last_edited: Option<DateTime<Utc>>,
pub privacy_level: PrivacyLevel,
pub other_keywords: String,
pub translated_keywords: String,
#[serde(default)]
pub translated_description: HashMap<String, String>,
pub cover: Option<LiteModule>,
pub age_ranges: Vec<AgeRangeId>,
pub affiliations: Vec<AffiliationId>,
pub categories: Vec<CategoryId>,
pub additional_resources: Vec<AdditionalResource>,
pub items: Vec<JigId>,
}
#[derive(Serialize, Deserialize, Debug, Clone, Copy, Eq, PartialEq)]
#[cfg_attr(feature = "backend", derive(sqlx::Type))]
#[serde(rename_all = "camelCase")]
#[repr(i16)]
pub enum PlaylistRating {
#[allow(missing_docs)]
One = 1,
#[allow(missing_docs)]
Two = 2,
#[allow(missing_docs)]
Three = 3,
}
impl TryFrom<u8> for PlaylistRating {
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, Clone, Debug, Default)]
#[serde(rename_all = "camelCase")]
pub struct PlaylistAdminData {
#[serde(default)]
pub rating: Option<PlaylistRating>,
pub blocked: bool,
pub curated: bool,
pub premium: bool,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(rename_all = "camelCase")]
pub struct PlaylistResponse {
pub id: PlaylistId,
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 is_liked: bool,
pub playlist_data: PlaylistData,
pub admin_data: PlaylistAdminData,
}
make_path_parts!(PlaylistGetLivePath => "/v1/playlist/{}/live" => PlaylistId);
make_path_parts!(PlaylistGetDraftPath => "/v1/playlist/{}/draft" => PlaylistId);
make_path_parts!(PlaylistUpdateDraftDataPath => "/v1/playlist/{}" => PlaylistId);
#[derive(Serialize, Deserialize, Debug, Default)]
#[serde(rename_all = "camelCase")]
pub struct PlaylistUpdateDraftDataRequest {
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(default)]
pub display_name: Option<String>,
#[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 language: Option<String>,
#[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>,
#[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 items: Option<Vec<JigId>>,
}
make_path_parts!(PlaylistPublishPath => "/v1/playlist/{}/draft/publish" => PlaylistId);
make_path_parts!(PlaylistBrowsePath => "/v1/playlist/browse");
#[derive(Serialize, Deserialize, Clone, Debug, Default)]
#[serde(rename_all = "camelCase")]
pub struct PlaylistBrowseQuery {
#[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 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>,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
#[serde(rename_all = "camelCase")]
pub struct PlaylistBrowseResponse {
pub playlists: Vec<PlaylistResponse>,
pub pages: u32,
pub total_playlist_count: u64,
}
make_path_parts!(PlaylistSearchPath => "/v1/playlist");
#[derive(Serialize, Deserialize, Clone, Debug, Default)]
#[serde(rename_all = "camelCase")]
pub struct PlaylistSearchQuery {
#[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(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 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 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(serialize_with = "super::csv_encode_uuids")]
#[serde(deserialize_with = "super::from_csv")]
#[serde(skip_serializing_if = "Vec::is_empty")]
pub items: Vec<JigId>,
#[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 PlaylistSearchResponse {
pub playlists: Vec<PlaylistResponse>,
pub pages: u32,
pub total_playlist_count: u64,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct PlaylistLikedResponse {
pub is_liked: bool,
}
#[derive(Serialize, Deserialize, Clone, Debug, Default)]
#[serde(rename_all = "camelCase")]
pub struct PlaylistUpdateAdminDataRequest {
#[serde(default, skip_serializing_if = "UpdateNonNullable::is_keep")]
pub rating: UpdateNonNullable<PlaylistRating>,
#[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>,
}
make_path_parts!(PlaylistDeletePath => "/v1/playlist/{}" => PlaylistId);
make_path_parts!(PlaylistClonePath => "/v1/playlist/{}/clone" => PlaylistId);
make_path_parts!(PlaylistLikePath => "/v1/playlist/{}/like" => PlaylistId);
make_path_parts!(PlaylistUnlikePath => "/v1/playlist/{}/unlike" => PlaylistId);
make_path_parts!(PlaylistLikedPath => "/v1/playlist/{}/like" => PlaylistId);
make_path_parts!(ListLikedPath => "/v1/playlist/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>,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
#[serde(rename_all = "camelCase")]
pub struct ListLikedResponse {
pub playlists: Vec<PlaylistResponse>,
pub total_playlist_count: u64,
}
make_path_parts!(PlaylistViewPath => "/v1/playlist/{}/view" => PlaylistId);
make_path_parts!(PlaylistAdminDataUpdatePath => "/v1/playlist/{}/admin" => PlaylistId);
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct AdminPlaylistExport {
pub id: PlaylistId,
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<PlaylistRating>,
pub privacy_level: PrivacyLevel,
pub created_at: DateTime<Utc>,
pub published_at: Option<DateTime<Utc>>,
pub language: String,
}