use std::collections::HashSet;
use axum::Json;
use axum::extract::State;
use entertainarr_domain::podcast::entity::ListPodcastResponse;
use entertainarr_domain::podcast::prelude::PodcastService;
use entertainarr_domain::prelude::Page;
use serde_qs::axum::QsQuery;
use crate::entity::podcast::{
PodcastAttributes, PodcastDocument, PodcastInclude, PodcastRelation, PodcastRelationships,
};
use crate::entity::podcast_subscription::{
PodcastSubscriptionAttributes, PodcastSubscriptionDocument, 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,
QsQuery(params): QsQuery<FindQueryParams<PodcastInclude>>,
) -> Result<Json<ApiResource<Vec<PodcastDocument>, PodcastRelation>>, ApiErrorResponse>
where
S: crate::server::prelude::ServerState,
{
let response = state
.podcast_service()
.list_podcast(entertainarr_domain::podcast::entity::ListPodcastParams {
user_id: Some(user_id),
filter: entertainarr_domain::podcast::entity::ListPodcastFilter {
podcast_ids: &[],
subscribed: Some(true),
},
page: Page {
limit: 100,
offset: 0,
},
})
.await
.map_err(|err| {
tracing::error!(error = ?err, "unable to list user podcasts");
ApiErrorResponse::internal()
})?;
Ok(Json(ApiResource::from_response(response, params.include)))
}
impl FromDomainResponse<ListPodcastResponse, PodcastInclude>
for ApiResource<Vec<PodcastDocument>, PodcastRelation>
{
fn from_response(response: ListPodcastResponse, required: HashSet<PodcastInclude>) -> Self {
let data = response
.podcasts
.into_iter()
.map(|podcast| PodcastDocument {
id: podcast.id,
kind: Default::default(),
relationships: PodcastRelationships {
subscription: Relation {
data: response.subscriptions.get(&podcast.id).map(|sub| {
PodcastSubscriptionEntity::new(Couple(sub.podcast_id, sub.user_id))
}),
meta: None,
},
synchronization: Relation {
data: response
.synchronizations
.get(&podcast.id)
.map(|sync| TaskEntity::new(sync.id)),
meta: (),
},
},
attributes: PodcastAttributes::from(podcast),
})
.collect();
let mut includes = Vec::with_capacity(2);
if required.contains(&PodcastInclude::Subscription) {
includes.extend(response.subscriptions.into_values().map(|sub| {
PodcastRelation::PocastSubscription(PodcastSubscriptionDocument {
id: Couple(sub.podcast_id, sub.user_id),
kind: Default::default(),
attributes: PodcastSubscriptionAttributes {
min_duration: sub.min_duration,
max_duration: sub.max_duration,
created_at: sub.created_at,
},
})
}));
}
if required.contains(&PodcastInclude::Synchronization) {
includes.extend(
response
.synchronizations
.into_values()
.map(|sync| PodcastRelation::Task(sync.into())),
);
}
ApiResource { data, includes }
}
}