use axum::Json;
use axum::extract::{Path, State};
use entertainarr_domain::podcast::entity::PodcastSubscriptionUpdate;
use entertainarr_domain::podcast::prelude::PodcastService;
use crate::entity::ApiResource;
use crate::entity::podcast_subscription::PodcastSubscriptionUpdateDocument;
use crate::server::extractor::user::CurrentUser;
use crate::server::handler::error::ApiErrorResponse;
pub async fn handle<S>(
State(state): State<S>,
CurrentUser(user_id): CurrentUser,
Path(podcast_id): Path<u64>,
Json(payload): Json<ApiResource<PodcastSubscriptionUpdateDocument>>,
) -> Result<axum::http::StatusCode, ApiErrorResponse>
where
S: crate::server::prelude::ServerState,
{
state
.podcast_service()
.update_subscription_by_id(
user_id,
podcast_id,
PodcastSubscriptionUpdate {
min_duration: payload.data.attributes.min_duration,
max_duration: payload.data.attributes.max_duration,
},
)
.await
.map(|_| axum::http::StatusCode::NO_CONTENT)
.map_err(|err| {
tracing::error!(error = ?err, "unable to update subscription");
ApiErrorResponse::internal()
})
}
#[cfg(test)]
mod tests {
use axum::Json;
use axum::extract::{Path, State};
use axum::http::StatusCode;
use entertainarr_domain::podcast::prelude::MockPodcastService;
use crate::entity::podcast_subscription::{
PodcastSubscriptionUpdateAttributes, PodcastSubscriptionUpdateDocument,
};
use crate::entity::{ApiResource, Couple};
use crate::server::extractor::user::CurrentUser;
use crate::server::prelude::tests::MockServerState;
#[tokio::test]
async fn should_fail_if_service_fails() {
let mut podcast_service = MockPodcastService::new();
podcast_service
.expect_update_subscription_by_id()
.return_once(|user_id, podcast_id, _feed_url| {
assert_eq!(user_id, 1);
assert_eq!(podcast_id, 2);
Box::pin(async move { Err(anyhow::anyhow!("oops")) })
});
let state = MockServerState::builder().podcast(podcast_service).build();
let err = super::handle(
State(state),
CurrentUser(1),
Path(2),
Json(ApiResource::new(PodcastSubscriptionUpdateDocument {
id: Couple(2, 1),
kind: Default::default(),
attributes: PodcastSubscriptionUpdateAttributes {
min_duration: Some(12),
max_duration: None,
},
})),
)
.await
.unwrap_err();
assert_eq!(err.status_code, StatusCode::INTERNAL_SERVER_ERROR);
}
#[tokio::test]
async fn should_succeed() {
let mut podcast_service = MockPodcastService::new();
podcast_service
.expect_update_subscription_by_id()
.return_once(|user_id, podcast_id, _| {
assert_eq!(user_id, 1);
assert_eq!(podcast_id, 2);
Box::pin(async move { Ok(()) })
});
let state = MockServerState::builder().podcast(podcast_service).build();
let res = super::handle(
State(state),
CurrentUser(1),
Path(2),
Json(ApiResource::new(PodcastSubscriptionUpdateDocument {
id: Couple(2, 1),
kind: Default::default(),
attributes: PodcastSubscriptionUpdateAttributes {
min_duration: Some(12),
max_duration: None,
},
})),
)
.await
.unwrap();
assert_eq!(res, StatusCode::NO_CONTENT);
}
}