feat: add WatchMedium field, general review editing, configurable deploy
Some checks failed
CI / Check / Test (push) Failing after 27m0s
Some checks failed
CI / Check / Test (push) Failing after 27m0s
- WatchMedium enum (cinema/streaming/tv/physical_media/download/media_server/other) - PATCH /api/v1/reviews/:id partial update (rating, comment, watched_at, watch_medium) - edit_review use case w/ ownership + remote review guard, best-effort AP Update broadcast - SPA: icon picker, edit sheet (long-press mobile / pencil desktop), watch medium badge - shared ReviewFormFields, EditableContextMenu, parse_watched_at/format_watched_at - deploy.sh parameterized (--features, --tag), CORS allows PATCH - CONTEXT.md glossary, ADR-0001 general review editing
This commit is contained in:
60
crates/application/src/diary/edit_review.rs
Normal file
60
crates/application/src/diary/edit_review.rs
Normal file
@@ -0,0 +1,60 @@
|
||||
use crate::diary::{commands::EditReviewCommand, deps::EditReviewDeps};
|
||||
use domain::{
|
||||
errors::DomainError,
|
||||
events::DomainEvent,
|
||||
models::ReviewEdit,
|
||||
value_objects::{Comment, Rating, ReviewId, UserId},
|
||||
};
|
||||
|
||||
pub async fn execute(deps: &EditReviewDeps, cmd: EditReviewCommand) -> Result<(), DomainError> {
|
||||
let review_id = ReviewId::from_uuid(cmd.review_id);
|
||||
let requesting_user_id = UserId::from_uuid(cmd.requesting_user_id);
|
||||
|
||||
let review = deps
|
||||
.review
|
||||
.get_review_by_id(&review_id)
|
||||
.await?
|
||||
.ok_or_else(|| DomainError::NotFound(format!("review {}", cmd.review_id)))?;
|
||||
|
||||
if review.is_remote() {
|
||||
return Err(DomainError::Forbidden(
|
||||
"cannot edit a federated review".into(),
|
||||
));
|
||||
}
|
||||
|
||||
if review.user_id() != &requesting_user_id {
|
||||
return Err(DomainError::Forbidden("not your review".into()));
|
||||
}
|
||||
|
||||
let updated = review.apply_edit(ReviewEdit {
|
||||
rating: cmd.rating.map(Rating::new).transpose()?,
|
||||
comment: cmd
|
||||
.comment
|
||||
.map(|c| c.map(Comment::new).transpose())
|
||||
.transpose()?,
|
||||
watched_at: cmd.watched_at,
|
||||
watch_medium: cmd.watch_medium,
|
||||
});
|
||||
|
||||
deps.review.update_review(&updated).await?;
|
||||
|
||||
if let Err(e) = deps
|
||||
.event_publisher
|
||||
.publish(&DomainEvent::ReviewUpdated {
|
||||
review_id: updated.id().clone(),
|
||||
movie_id: updated.movie_id().clone(),
|
||||
user_id: updated.user_id().clone(),
|
||||
rating: updated.rating().clone(),
|
||||
watched_at: *updated.watched_at(),
|
||||
})
|
||||
.await
|
||||
{
|
||||
tracing::warn!("failed to publish ReviewUpdated: {e}");
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[path = "tests/edit_review.rs"]
|
||||
mod tests;
|
||||
Reference in New Issue
Block a user