use std::collections::HashSet;
use axum::Json;
use axum::extract::{Path, State};
use entertainarr_domain::podcast::entity::FindPodcastEpisodeResponse;
use entertainarr_domain::podcast::prelude::PodcastService;
use serde_qs::axum::QsQuery;
use crate::entity::podcast::{PodcastDocument, PodcastEntity, PodcastRelationships};
use crate::entity::podcast_episode::{
PodcastEpisodeDocument, PodcastEpisodeInclude, PodcastEpisodeProgressEntity,
PodcastEpisodeRelation, PodcastEpisodeRelationships,
};
use crate::entity::podcast_subscription::PodcastSubscriptionEntity;
use crate::entity::prelude::FindQueryParams;
use crate::entity::task::TaskEntity;
use crate::entity::{ApiResource, Couple, Relation};
use crate::server::extractor::user::CurrentUser;
use crate::server::handler::error::ApiErrorResponse;
use crate::server::handler::prelude::FromDomainResponse;
pub async fn handle<S>(
State(state): State<S>,
CurrentUser(user_id): CurrentUser,
Path(episode_id): Path<u64>,
QsQuery(params): QsQuery<FindQueryParams<PodcastEpisodeInclude>>,
) -> Result<Json<ApiResource<PodcastEpisodeDocument, PodcastEpisodeRelation>>, ApiErrorResponse>
where
S: crate::server::prelude::ServerState,
{
let response = state
.podcast_service()
.find_podcast_episode_by_id(user_id, episode_id)
.await
.map_err(|err| {
tracing::error!(error = ?err, "unable to fetch podcast episode");
ApiErrorResponse::internal()
})?
.ok_or_else(|| ApiErrorResponse::not_found("podcast episode not found"))?;
Ok(Json(ApiResource::from_response(response, params.include)))
}
impl FromDomainResponse<FindPodcastEpisodeResponse, PodcastEpisodeInclude>
for ApiResource<PodcastEpisodeDocument, PodcastEpisodeRelation>
{
fn from_response(
response: FindPodcastEpisodeResponse,
required: HashSet<PodcastEpisodeInclude>,
) -> Self {
let data = PodcastEpisodeDocument {
id: response.episode.id,
kind: Default::default(),
relationships: PodcastEpisodeRelationships {
podcast: Relation {
data: Some(PodcastEntity::new(response.episode.podcast_id)),
meta: (),
},
progress: Relation {
data: response.progress.as_ref().map(|p| {
PodcastEpisodeProgressEntity::new(Couple(p.podcast_episode_id, p.user_id))
}),
meta: (),
},
},
attributes: response.episode.into(),
};
let mut includes = Vec::with_capacity(2);
if required.contains(&PodcastEpisodeInclude::Podcast) {
includes.push(PodcastEpisodeRelation::Podcast(PodcastDocument {
id: response.podcast.id,
kind: Default::default(),
relationships: PodcastRelationships {
subscription: Relation {
data: response.subscription.as_ref().map(|s| {
PodcastSubscriptionEntity::new(Couple(s.podcast_id, s.user_id))
}),
meta: None,
},
synchronization: Relation {
data: response
.synchronization
.as_ref()
.map(|s| TaskEntity::new(s.id)),
meta: (),
},
},
attributes: response.podcast.into(),
}));
}
if required.contains(&PodcastEpisodeInclude::PodcastEpisodeProgress)
&& let Some(progress) = response.progress
{
includes.push(PodcastEpisodeRelation::PodcastEpisodeProgress(
progress.into(),
));
}
ApiResource { data, includes }
}
}