Files
movies-diary/crates/domain/src/events.rs
Gabriel Kaszewski 7e02f15a85 refactor: consolidate 11 social use cases → SocialCmd/SocialQry enum dispatch
-280 net lines. 11 one-file use cases replaced by execute_command/
execute_query with enum dispatch. Added FollowRejected event (reject
was silently dropping). Command→event mapping now explicit in one match.
2026-07-10 16:26:57 +02:00

175 lines
4.0 KiB
Rust

use async_trait::async_trait;
use chrono::NaiveDateTime;
use crate::{
errors::DomainError,
models::{ExternalPersonId, PersonId},
value_objects::{
ExternalMetadataId, GoalId, MovieId, PosterPath, Rating, ReviewId, UserId, WrapUpId,
},
};
#[derive(Clone, Debug)]
pub enum DomainEvent {
ReviewLogged {
review_id: ReviewId,
movie_id: MovieId,
user_id: UserId,
rating: Rating,
watched_at: NaiveDateTime,
},
ReviewUpdated {
review_id: ReviewId,
movie_id: MovieId,
user_id: UserId,
rating: Rating,
watched_at: NaiveDateTime,
},
MovieDiscovered {
movie_id: MovieId,
external_metadata_id: ExternalMetadataId,
},
MovieDeleted {
movie_id: MovieId,
poster_path: Option<PosterPath>,
},
UserUpdated {
user_id: UserId,
},
ReviewDeleted {
review_id: ReviewId,
user_id: UserId,
},
MovieEnrichmentRequested {
movie_id: MovieId,
external_metadata_id: ExternalMetadataId,
},
PersonEnrichmentRequested {
person_id: PersonId,
external_person_id: ExternalPersonId,
},
ImageStored {
key: String,
},
WatchlistEntryAdded {
user_id: UserId,
movie_id: MovieId,
movie_title: String,
release_year: u16,
external_metadata_id: Option<String>,
added_at: chrono::NaiveDateTime,
},
WatchlistEntryRemoved {
user_id: UserId,
movie_id: MovieId,
},
FollowRequested {
follower: UserId,
target: crate::value_objects::FollowTarget,
},
FollowAccepted {
owner: UserId,
requester: crate::value_objects::SocialIdentity,
},
FollowRejected {
owner: UserId,
requester: crate::value_objects::SocialIdentity,
},
Unfollowed {
follower: UserId,
target: crate::value_objects::SocialIdentity,
},
FollowerRemoved {
owner: UserId,
follower: crate::value_objects::SocialIdentity,
},
ActorBlocked {
blocker: UserId,
target: crate::value_objects::SocialIdentity,
},
ActorUnblocked {
blocker: UserId,
target: crate::value_objects::SocialIdentity,
},
BackfillFollower {
owner_user_id: UserId,
follower_inbox_url: String,
},
FederationDeliveryRequested {
inbox_url: String,
activity_json: serde_json::Value,
signing_actor_id: uuid::Uuid,
},
WatchEventIngested {
user_id: UserId,
title: String,
source: String,
},
WrapUpRequested {
wrapup_id: WrapUpId,
user_id: Option<UserId>,
start_date: chrono::NaiveDate,
end_date: chrono::NaiveDate,
},
WrapUpCompleted {
wrapup_id: WrapUpId,
},
SearchReindexRequested,
PosterSynced {
movie_id: MovieId,
},
GoalCreated {
goal_id: GoalId,
user_id: UserId,
year: u16,
target_count: u32,
},
GoalUpdated {
goal_id: GoalId,
user_id: UserId,
year: u16,
target_count: u32,
},
GoalDeleted {
goal_id: GoalId,
user_id: UserId,
year: u16,
},
UserDeleted {
user_id: UserId,
},
UserAccountMoved {
user_id: UserId,
new_actor_url: String,
},
}
#[async_trait]
pub trait AckHandle: Send + Sync {
async fn ack(&self) -> Result<(), DomainError>;
async fn nack(&self) -> Result<(), DomainError>;
}
pub struct EventEnvelope {
pub event: DomainEvent,
ack: Box<dyn AckHandle>,
}
impl EventEnvelope {
pub fn new(event: DomainEvent, ack: Box<dyn AckHandle>) -> Self {
Self { event, ack }
}
pub async fn ack(self) -> Result<(), DomainError> {
self.ack.ack().await
}
pub async fn nack(self) -> Result<(), DomainError> {
self.ack.nack().await
}
}
#[cfg(test)]
#[path = "tests/events.rs"]
mod tests;