181 lines
4.9 KiB
Rust
181 lines
4.9 KiB
Rust
use crate::users::{
|
|
deps::GetProfileDeps,
|
|
queries::{GetUserProfileQuery, ProfileView},
|
|
};
|
|
use domain::{
|
|
errors::DomainError,
|
|
models::{
|
|
DiaryEntry, DiaryFilter, SortDirection, UserStats, UserTrends,
|
|
collections::{PageParams, Paginated},
|
|
},
|
|
ports::FeedSortBy,
|
|
value_objects::UserId,
|
|
};
|
|
|
|
pub struct PendingFollowerView {
|
|
pub url: String,
|
|
pub handle: String,
|
|
pub display_name: Option<String>,
|
|
pub avatar_url: Option<String>,
|
|
}
|
|
|
|
pub struct UserProfileData {
|
|
pub stats: UserStats,
|
|
pub entries: Option<Paginated<DiaryEntry>>,
|
|
pub history: Option<Vec<DiaryEntry>>,
|
|
pub trends: Option<UserTrends>,
|
|
pub following_count: usize,
|
|
pub followers_count: usize,
|
|
pub pending_followers: Vec<PendingFollowerView>,
|
|
}
|
|
|
|
pub async fn execute(
|
|
deps: &GetProfileDeps,
|
|
query: GetUserProfileQuery,
|
|
) -> Result<UserProfileData, DomainError> {
|
|
let user_id = UserId::from_uuid(query.user_id);
|
|
let stats = deps.stats.get_user_stats(&user_id).await?;
|
|
|
|
let (following_count, followers_count, pending_followers) =
|
|
load_social_counts(deps, query.user_id, query.is_own_profile).await;
|
|
|
|
let base = |entries, history, trends| UserProfileData {
|
|
stats,
|
|
entries,
|
|
history,
|
|
trends,
|
|
following_count,
|
|
followers_count,
|
|
pending_followers,
|
|
};
|
|
|
|
match query.view {
|
|
ProfileView::History => {
|
|
let all_entries = deps.diary.get_user_history(&user_id).await?;
|
|
Ok(base(None, Some(all_entries), None))
|
|
}
|
|
ProfileView::Trends => {
|
|
let trends = deps.stats.get_user_trends(&user_id).await?;
|
|
Ok(base(None, None, Some(trends)))
|
|
}
|
|
ProfileView::Ratings | ProfileView::Recent => {
|
|
let sort_direction = feed_sort_to_direction(query.sort_by);
|
|
let filter = paged_user_filter(
|
|
user_id,
|
|
sort_direction,
|
|
query.limit,
|
|
query.offset,
|
|
query.search.clone(),
|
|
)?;
|
|
let entries = deps.diary.query_diary(&filter).await?;
|
|
Ok(base(Some(entries), None, None))
|
|
}
|
|
}
|
|
}
|
|
|
|
async fn load_social_counts(
|
|
deps: &GetProfileDeps,
|
|
user_id: uuid::Uuid,
|
|
is_own_profile: bool,
|
|
) -> (usize, usize, Vec<PendingFollowerView>) {
|
|
let following = deps
|
|
.social_query
|
|
.count_following(user_id)
|
|
.await
|
|
.unwrap_or(0);
|
|
let followers = deps
|
|
.social_query
|
|
.count_accepted_followers(user_id)
|
|
.await
|
|
.unwrap_or(0);
|
|
if !is_own_profile {
|
|
return (following, followers, vec![]);
|
|
}
|
|
let pending = deps
|
|
.social_query
|
|
.get_pending_followers(user_id)
|
|
.await
|
|
.unwrap_or_default()
|
|
.into_iter()
|
|
.map(|p| PendingFollowerView {
|
|
url: p.url,
|
|
handle: p.handle,
|
|
display_name: p.display_name,
|
|
avatar_url: p.avatar_url,
|
|
})
|
|
.collect();
|
|
(following, followers, pending)
|
|
}
|
|
|
|
fn feed_sort_to_direction(sort_by: FeedSortBy) -> SortDirection {
|
|
match sort_by {
|
|
FeedSortBy::Date => SortDirection::Descending,
|
|
FeedSortBy::DateAsc => SortDirection::Ascending,
|
|
FeedSortBy::Rating => SortDirection::ByRatingDesc,
|
|
FeedSortBy::RatingAsc => SortDirection::ByRatingAsc,
|
|
}
|
|
}
|
|
|
|
fn paged_user_filter(
|
|
user_id: UserId,
|
|
sort_by: SortDirection,
|
|
limit: Option<u32>,
|
|
offset: Option<u32>,
|
|
search: Option<String>,
|
|
) -> Result<DiaryFilter, DomainError> {
|
|
let page = PageParams::new(limit, offset)?;
|
|
Ok(DiaryFilter {
|
|
sort_by,
|
|
page,
|
|
movie_id: None,
|
|
user_id: Some(user_id),
|
|
search,
|
|
})
|
|
}
|
|
|
|
#[cfg(test)]
|
|
#[path = "tests/get_profile.rs"]
|
|
mod tests;
|
|
|
|
#[cfg(test)]
|
|
mod helper_tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn feed_sort_to_direction_all_variants() {
|
|
use domain::ports::FeedSortBy;
|
|
assert!(matches!(
|
|
feed_sort_to_direction(FeedSortBy::Date),
|
|
SortDirection::Descending
|
|
));
|
|
assert!(matches!(
|
|
feed_sort_to_direction(FeedSortBy::DateAsc),
|
|
SortDirection::Ascending
|
|
));
|
|
assert!(matches!(
|
|
feed_sort_to_direction(FeedSortBy::Rating),
|
|
SortDirection::ByRatingDesc
|
|
));
|
|
assert!(matches!(
|
|
feed_sort_to_direction(FeedSortBy::RatingAsc),
|
|
SortDirection::ByRatingAsc
|
|
));
|
|
}
|
|
|
|
#[test]
|
|
fn paged_user_filter_builds_correctly() {
|
|
let uid = UserId::from_uuid(uuid::Uuid::new_v4());
|
|
let filter = paged_user_filter(
|
|
uid.clone(),
|
|
SortDirection::Descending,
|
|
Some(20),
|
|
Some(5),
|
|
Some("blade".into()),
|
|
)
|
|
.unwrap();
|
|
|
|
assert_eq!(filter.user_id.unwrap().value(), uid.value());
|
|
assert_eq!(filter.search.as_deref(), Some("blade"));
|
|
}
|
|
}
|