@@ -36,7 +36,11 @@ RUN sqlite3 /build/dev.db \
|
||||
sqlite3 /build/dev.db \
|
||||
< crates/adapters/sqlite/migrations/0002_users.sql && \
|
||||
sqlite3 /build/dev.db \
|
||||
< crates/adapters/sqlite/migrations/0003_activitypub.sql
|
||||
< crates/adapters/sqlite/migrations/0003_activitypub.sql && \
|
||||
sqlite3 /build/dev.db \
|
||||
< crates/adapters/sqlite/migrations/0004_username.sql && \
|
||||
sqlite3 /build/dev.db \
|
||||
< crates/adapters/sqlite/migrations/0005_activitypub_v2.sql
|
||||
|
||||
ENV DATABASE_URL=sqlite:///build/dev.db
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use chrono::NaiveDateTime;
|
||||
use domain::models::ExportFormat;
|
||||
use uuid::Uuid;
|
||||
|
||||
pub struct LogReviewCommand {
|
||||
@@ -35,3 +36,8 @@ pub struct DeleteReviewCommand {
|
||||
pub review_id: Uuid,
|
||||
pub requesting_user_id: Uuid,
|
||||
}
|
||||
|
||||
pub struct ExportCommand {
|
||||
pub user_id: Uuid,
|
||||
pub format: ExportFormat,
|
||||
}
|
||||
|
||||
23
crates/application/src/use_cases/export_diary.rs
Normal file
23
crates/application/src/use_cases/export_diary.rs
Normal file
@@ -0,0 +1,23 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use domain::{
|
||||
errors::DomainError,
|
||||
ports::{DiaryExporter, MovieRepository},
|
||||
};
|
||||
|
||||
use crate::commands::ExportCommand;
|
||||
|
||||
pub struct ExportDiary {
|
||||
repository: Arc<dyn MovieRepository>,
|
||||
exporter: Arc<dyn DiaryExporter>,
|
||||
}
|
||||
|
||||
impl ExportDiary {
|
||||
pub async fn execute(&self, req: ExportCommand) -> Result<Vec<u8>, DomainError> {
|
||||
// 1. fetch all diary entries for the user
|
||||
// 2. delegate serialization to the port (exporter)
|
||||
|
||||
// Return bytes of the exported diary, which can be written to a file or returned in an HTTP response
|
||||
Ok(vec![])
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
pub mod delete_review;
|
||||
pub mod export_diary;
|
||||
pub mod get_activity_feed;
|
||||
pub mod get_diary;
|
||||
pub mod get_review_history;
|
||||
|
||||
@@ -262,7 +262,12 @@ pub struct User {
|
||||
|
||||
impl User {
|
||||
pub fn new(email: Email, username: Username, password_hash: PasswordHash) -> Self {
|
||||
Self { id: UserId::generate(), email, username, password_hash }
|
||||
Self {
|
||||
id: UserId::generate(),
|
||||
email,
|
||||
username,
|
||||
password_hash,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_persistence(
|
||||
@@ -271,17 +276,30 @@ impl User {
|
||||
username: Username,
|
||||
password_hash: PasswordHash,
|
||||
) -> Self {
|
||||
Self { id, email, username, password_hash }
|
||||
Self {
|
||||
id,
|
||||
email,
|
||||
username,
|
||||
password_hash,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update_password(&mut self, new_hash: PasswordHash) {
|
||||
self.password_hash = new_hash;
|
||||
}
|
||||
|
||||
pub fn email(&self) -> &Email { &self.email }
|
||||
pub fn username(&self) -> &Username { &self.username }
|
||||
pub fn id(&self) -> &UserId { &self.id }
|
||||
pub fn password_hash(&self) -> &PasswordHash { &self.password_hash }
|
||||
pub fn email(&self) -> &Email {
|
||||
&self.email
|
||||
}
|
||||
pub fn username(&self) -> &Username {
|
||||
&self.username
|
||||
}
|
||||
pub fn id(&self) -> &UserId {
|
||||
&self.id
|
||||
}
|
||||
pub fn password_hash(&self) -> &PasswordHash {
|
||||
&self.password_hash
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
@@ -294,11 +312,20 @@ impl FeedEntry {
|
||||
pub fn new(entry: DiaryEntry, user_email: String) -> Self {
|
||||
Self { entry, user_email }
|
||||
}
|
||||
pub fn movie(&self) -> &Movie { self.entry.movie() }
|
||||
pub fn review(&self) -> &Review { self.entry.review() }
|
||||
pub fn user_email(&self) -> &str { &self.user_email }
|
||||
pub fn movie(&self) -> &Movie {
|
||||
self.entry.movie()
|
||||
}
|
||||
pub fn review(&self) -> &Review {
|
||||
self.entry.review()
|
||||
}
|
||||
pub fn user_email(&self) -> &str {
|
||||
&self.user_email
|
||||
}
|
||||
pub fn user_display_name(&self) -> &str {
|
||||
self.user_email.split('@').next().unwrap_or(&self.user_email)
|
||||
self.user_email
|
||||
.split('@')
|
||||
.next()
|
||||
.unwrap_or(&self.user_email)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -312,9 +339,16 @@ pub struct UserSummary {
|
||||
|
||||
impl UserSummary {
|
||||
pub fn new(user_id: UserId, email: Email, total_movies: i64, avg_rating: Option<f64>) -> Self {
|
||||
Self { user_id, email, total_movies, avg_rating }
|
||||
Self {
|
||||
user_id,
|
||||
email,
|
||||
total_movies,
|
||||
avg_rating,
|
||||
}
|
||||
}
|
||||
pub fn email(&self) -> &str {
|
||||
self.email.value()
|
||||
}
|
||||
pub fn email(&self) -> &str { self.email.value() }
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
@@ -325,7 +359,6 @@ pub struct UserStats {
|
||||
pub most_active_month: Option<String>,
|
||||
}
|
||||
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct MonthActivity {
|
||||
pub year_month: String,
|
||||
@@ -354,3 +387,8 @@ pub struct UserTrends {
|
||||
pub top_directors: Vec<DirectorStat>,
|
||||
pub max_director_count: i64,
|
||||
}
|
||||
|
||||
pub enum ExportFormat {
|
||||
Csv,
|
||||
Json,
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ use crate::{
|
||||
events::DomainEvent,
|
||||
models::{
|
||||
DiaryEntry, DiaryFilter, FeedEntry, Movie, Review, ReviewHistory, User, UserStats,
|
||||
UserTrends, UserSummary,
|
||||
UserSummary, UserTrends,
|
||||
collections::{PageParams, Paginated},
|
||||
},
|
||||
value_objects::{
|
||||
@@ -57,7 +57,10 @@ pub trait MovieRepository: Send + Sync {
|
||||
|
||||
pub enum MetadataSearchCriteria {
|
||||
ImdbId(ExternalMetadataId),
|
||||
Title { title: MovieTitle, year: Option<ReleaseYear> },
|
||||
Title {
|
||||
title: MovieTitle,
|
||||
year: Option<ReleaseYear>,
|
||||
},
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
@@ -119,3 +122,8 @@ pub trait PasswordHasher: Send + Sync {
|
||||
|
||||
async fn verify(&self, plain_password: &str, hash: &PasswordHash) -> Result<bool, DomainError>;
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
pub trait DiaryExporter: Send + Sync {
|
||||
async fn serialize_reviews(&self, reviews: &[Review]) -> Result<Vec<u8>, DomainError>;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user