refactor(users): GetProfileDeps, UpdateProfileDeps, scoped Arc deps
This commit is contained in:
18
crates/application/src/users/deps.rs
Normal file
18
crates/application/src/users/deps.rs
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use domain::ports::{
|
||||||
|
DiaryRepository, EventPublisher, ObjectStorage, SocialQueryPort, StatsRepository,
|
||||||
|
UserRepository,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct GetProfileDeps {
|
||||||
|
pub stats: Arc<dyn StatsRepository>,
|
||||||
|
pub diary: Arc<dyn DiaryRepository>,
|
||||||
|
pub social_query: Arc<dyn SocialQueryPort>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct UpdateProfileDeps {
|
||||||
|
pub user: Arc<dyn UserRepository>,
|
||||||
|
pub object_storage: Arc<dyn ObjectStorage>,
|
||||||
|
pub event_publisher: Arc<dyn EventPublisher>,
|
||||||
|
}
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
use domain::errors::DomainError;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use crate::{context::AppContext, users::queries::GetCurrentProfileQuery};
|
use domain::{errors::DomainError, ports::UserRepository};
|
||||||
|
|
||||||
|
use crate::users::queries::GetCurrentProfileQuery;
|
||||||
|
|
||||||
pub struct ProfileFieldData {
|
pub struct ProfileFieldData {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
@@ -19,18 +21,16 @@ pub struct CurrentProfileData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn execute(
|
pub async fn execute(
|
||||||
ctx: &AppContext,
|
user: Arc<dyn UserRepository>,
|
||||||
query: GetCurrentProfileQuery,
|
query: GetCurrentProfileQuery,
|
||||||
) -> Result<CurrentProfileData, DomainError> {
|
) -> Result<CurrentProfileData, DomainError> {
|
||||||
let user_id = domain::value_objects::UserId::from_uuid(query.user_id);
|
let user_id = domain::value_objects::UserId::from_uuid(query.user_id);
|
||||||
let user = ctx
|
let found = user
|
||||||
.repos
|
|
||||||
.user
|
|
||||||
.find_by_id(&user_id)
|
.find_by_id(&user_id)
|
||||||
.await?
|
.await?
|
||||||
.ok_or_else(|| DomainError::NotFound("User not found".into()))?;
|
.ok_or_else(|| DomainError::NotFound("User not found".into()))?;
|
||||||
|
|
||||||
let fields = user
|
let fields = found
|
||||||
.profile_fields()
|
.profile_fields()
|
||||||
.iter()
|
.iter()
|
||||||
.map(|f| ProfileFieldData {
|
.map(|f| ProfileFieldData {
|
||||||
@@ -40,14 +40,14 @@ pub async fn execute(
|
|||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
Ok(CurrentProfileData {
|
Ok(CurrentProfileData {
|
||||||
username: user.username().value().to_string(),
|
username: found.username().value().to_string(),
|
||||||
display_name: user.display_name().map(|s| s.to_string()),
|
display_name: found.display_name().map(|s| s.to_string()),
|
||||||
bio: user.bio().map(|s| s.to_string()),
|
bio: found.bio().map(|s| s.to_string()),
|
||||||
avatar_path: user.avatar_path().map(|s| s.to_string()),
|
avatar_path: found.avatar_path().map(|s| s.to_string()),
|
||||||
banner_path: user.banner_path().map(|s| s.to_string()),
|
banner_path: found.banner_path().map(|s| s.to_string()),
|
||||||
also_known_as: user.also_known_as().map(|s| s.to_string()),
|
also_known_as: found.also_known_as().map(|s| s.to_string()),
|
||||||
fields,
|
fields,
|
||||||
role: user.role().as_str().into(),
|
role: found.role().as_str().into(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use crate::{
|
use crate::users::{
|
||||||
context::AppContext,
|
deps::GetProfileDeps,
|
||||||
users::queries::{GetUserProfileQuery, ProfileView},
|
queries::{GetUserProfileQuery, ProfileView},
|
||||||
};
|
};
|
||||||
use domain::{
|
use domain::{
|
||||||
errors::DomainError,
|
errors::DomainError,
|
||||||
@@ -30,14 +30,14 @@ pub struct UserProfileData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn execute(
|
pub async fn execute(
|
||||||
ctx: &AppContext,
|
deps: &GetProfileDeps,
|
||||||
query: GetUserProfileQuery,
|
query: GetUserProfileQuery,
|
||||||
) -> Result<UserProfileData, DomainError> {
|
) -> Result<UserProfileData, DomainError> {
|
||||||
let user_id = UserId::from_uuid(query.user_id);
|
let user_id = UserId::from_uuid(query.user_id);
|
||||||
let stats = ctx.repos.stats.get_user_stats(&user_id).await?;
|
let stats = deps.stats.get_user_stats(&user_id).await?;
|
||||||
|
|
||||||
let (following_count, followers_count, pending_followers) =
|
let (following_count, followers_count, pending_followers) =
|
||||||
load_social_counts(ctx, query.user_id, query.is_own_profile).await;
|
load_social_counts(deps, query.user_id, query.is_own_profile).await;
|
||||||
|
|
||||||
let base = |entries, history, trends| UserProfileData {
|
let base = |entries, history, trends| UserProfileData {
|
||||||
stats,
|
stats,
|
||||||
@@ -51,11 +51,11 @@ pub async fn execute(
|
|||||||
|
|
||||||
match query.view {
|
match query.view {
|
||||||
ProfileView::History => {
|
ProfileView::History => {
|
||||||
let all_entries = ctx.repos.diary.get_user_history(&user_id).await?;
|
let all_entries = deps.diary.get_user_history(&user_id).await?;
|
||||||
Ok(base(None, Some(all_entries), None))
|
Ok(base(None, Some(all_entries), None))
|
||||||
}
|
}
|
||||||
ProfileView::Trends => {
|
ProfileView::Trends => {
|
||||||
let trends = ctx.repos.stats.get_user_trends(&user_id).await?;
|
let trends = deps.stats.get_user_trends(&user_id).await?;
|
||||||
Ok(base(None, None, Some(trends)))
|
Ok(base(None, None, Some(trends)))
|
||||||
}
|
}
|
||||||
ProfileView::Ratings | ProfileView::Recent => {
|
ProfileView::Ratings | ProfileView::Recent => {
|
||||||
@@ -67,25 +67,23 @@ pub async fn execute(
|
|||||||
query.offset,
|
query.offset,
|
||||||
query.search.clone(),
|
query.search.clone(),
|
||||||
)?;
|
)?;
|
||||||
let entries = ctx.repos.diary.query_diary(&filter).await?;
|
let entries = deps.diary.query_diary(&filter).await?;
|
||||||
Ok(base(Some(entries), None, None))
|
Ok(base(Some(entries), None, None))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn load_social_counts(
|
async fn load_social_counts(
|
||||||
ctx: &AppContext,
|
deps: &GetProfileDeps,
|
||||||
user_id: uuid::Uuid,
|
user_id: uuid::Uuid,
|
||||||
is_own_profile: bool,
|
is_own_profile: bool,
|
||||||
) -> (usize, usize, Vec<PendingFollowerView>) {
|
) -> (usize, usize, Vec<PendingFollowerView>) {
|
||||||
let following = ctx
|
let following = deps
|
||||||
.repos
|
|
||||||
.social_query
|
.social_query
|
||||||
.count_following(user_id)
|
.count_following(user_id)
|
||||||
.await
|
.await
|
||||||
.unwrap_or(0);
|
.unwrap_or(0);
|
||||||
let followers = ctx
|
let followers = deps
|
||||||
.repos
|
|
||||||
.social_query
|
.social_query
|
||||||
.count_accepted_followers(user_id)
|
.count_accepted_followers(user_id)
|
||||||
.await
|
.await
|
||||||
@@ -93,8 +91,7 @@ async fn load_social_counts(
|
|||||||
if !is_own_profile {
|
if !is_own_profile {
|
||||||
return (following, followers, vec![]);
|
return (following, followers, vec![]);
|
||||||
}
|
}
|
||||||
let pending = ctx
|
let pending = deps
|
||||||
.repos
|
|
||||||
.social_query
|
.social_query
|
||||||
.get_pending_followers(user_id)
|
.get_pending_followers(user_id)
|
||||||
.await
|
.await
|
||||||
|
|||||||
@@ -1,10 +1,13 @@
|
|||||||
use domain::{errors::DomainError, models::UserSettings, value_objects::UserId};
|
use std::sync::Arc;
|
||||||
|
|
||||||
use crate::context::AppContext;
|
use domain::{errors::DomainError, models::UserSettings, ports::UserSettingsRepository, value_objects::UserId};
|
||||||
|
|
||||||
pub async fn execute(ctx: &AppContext, user_id: uuid::Uuid) -> Result<UserSettings, DomainError> {
|
pub async fn execute(
|
||||||
|
user_settings: Arc<dyn UserSettingsRepository>,
|
||||||
|
user_id: uuid::Uuid,
|
||||||
|
) -> Result<UserSettings, DomainError> {
|
||||||
let uid = UserId::from_uuid(user_id);
|
let uid = UserId::from_uuid(user_id);
|
||||||
ctx.repos.user_settings.get(&uid).await
|
user_settings.get(&uid).await
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
use crate::{context::AppContext, users::queries::GetUsersQuery};
|
use std::sync::Arc;
|
||||||
use domain::{errors::DomainError, models::UserSummary, ports::RemoteActorInfo};
|
|
||||||
|
use crate::users::queries::GetUsersQuery;
|
||||||
|
use domain::{errors::DomainError, models::UserSummary, ports::{RemoteActorInfo, SocialQueryPort, UserRepository}};
|
||||||
|
|
||||||
pub struct UsersListData {
|
pub struct UsersListData {
|
||||||
pub users: Vec<UserSummary>,
|
pub users: Vec<UserSummary>,
|
||||||
@@ -7,12 +9,13 @@ pub struct UsersListData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn execute(
|
pub async fn execute(
|
||||||
ctx: &AppContext,
|
user: Arc<dyn UserRepository>,
|
||||||
|
social_query: Arc<dyn SocialQueryPort>,
|
||||||
_query: GetUsersQuery,
|
_query: GetUsersQuery,
|
||||||
) -> Result<UsersListData, DomainError> {
|
) -> Result<UsersListData, DomainError> {
|
||||||
let (users_result, actors_result) = tokio::join!(
|
let (users_result, actors_result) = tokio::join!(
|
||||||
ctx.repos.user.list_with_stats(),
|
user.list_with_stats(),
|
||||||
ctx.repos.social_query.list_all_followed_remote_actors()
|
social_query.list_all_followed_remote_actors()
|
||||||
);
|
);
|
||||||
|
|
||||||
Ok(UsersListData {
|
Ok(UsersListData {
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
pub mod commands;
|
pub mod commands;
|
||||||
|
pub mod deps;
|
||||||
pub mod get_current_profile;
|
pub mod get_current_profile;
|
||||||
pub mod get_profile;
|
pub mod get_profile;
|
||||||
pub mod get_settings;
|
pub mod get_settings;
|
||||||
|
|||||||
@@ -15,9 +15,9 @@ use crate::{
|
|||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn returns_profile_for_existing_user() {
|
async fn returns_profile_for_existing_user() {
|
||||||
let users = InMemoryUserRepository::new();
|
let users = InMemoryUserRepository::new();
|
||||||
let ctx = TestContextBuilder::new()
|
let b = TestContextBuilder::new().with_users(Arc::clone(&users) as _);
|
||||||
.with_users(Arc::clone(&users) as _)
|
let user_repo = b.user_repo.clone();
|
||||||
.build();
|
let ctx = b.build();
|
||||||
|
|
||||||
register::execute(
|
register::execute(
|
||||||
&ctx,
|
&ctx,
|
||||||
@@ -38,7 +38,7 @@ async fn returns_profile_for_existing_user() {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let profile = get_current_profile::execute(
|
let profile = get_current_profile::execute(
|
||||||
&ctx,
|
user_repo,
|
||||||
GetCurrentProfileQuery {
|
GetCurrentProfileQuery {
|
||||||
user_id: user.id().value(),
|
user_id: user.id().value(),
|
||||||
},
|
},
|
||||||
@@ -51,10 +51,11 @@ async fn returns_profile_for_existing_user() {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn fails_for_nonexistent_user() {
|
async fn fails_for_nonexistent_user() {
|
||||||
let ctx = TestContextBuilder::new().build();
|
let b = TestContextBuilder::new();
|
||||||
|
let user_repo = b.user_repo.clone();
|
||||||
|
|
||||||
let result = get_current_profile::execute(
|
let result = get_current_profile::execute(
|
||||||
&ctx,
|
user_repo,
|
||||||
GetCurrentProfileQuery {
|
GetCurrentProfileQuery {
|
||||||
user_id: Uuid::new_v4(),
|
user_id: Uuid::new_v4(),
|
||||||
},
|
},
|
||||||
@@ -89,12 +90,11 @@ async fn returns_profile_with_avatar_banner_and_fields() {
|
|||||||
);
|
);
|
||||||
users.store.lock().unwrap().insert(uid.value(), user);
|
users.store.lock().unwrap().insert(uid.value(), user);
|
||||||
|
|
||||||
let ctx = TestContextBuilder::new()
|
let b = TestContextBuilder::new().with_users(Arc::clone(&users) as _);
|
||||||
.with_users(Arc::clone(&users) as _)
|
let user_repo = b.user_repo.clone();
|
||||||
.build();
|
|
||||||
|
|
||||||
let profile = get_current_profile::execute(
|
let profile = get_current_profile::execute(
|
||||||
&ctx,
|
user_repo,
|
||||||
GetCurrentProfileQuery {
|
GetCurrentProfileQuery {
|
||||||
user_id: uid.value(),
|
user_id: uid.value(),
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -4,12 +4,28 @@ use domain::value_objects::Email;
|
|||||||
use crate::auth::commands::RegisterCommand;
|
use crate::auth::commands::RegisterCommand;
|
||||||
use crate::auth::register;
|
use crate::auth::register;
|
||||||
use crate::test_helpers::TestContextBuilder;
|
use crate::test_helpers::TestContextBuilder;
|
||||||
|
use crate::users::deps::GetProfileDeps;
|
||||||
use crate::users::get_profile;
|
use crate::users::get_profile;
|
||||||
use crate::users::queries::{GetUserProfileQuery, ProfileView};
|
use crate::users::queries::{GetUserProfileQuery, ProfileView};
|
||||||
|
|
||||||
|
fn default_deps() -> GetProfileDeps {
|
||||||
|
let b = TestContextBuilder::new();
|
||||||
|
GetProfileDeps {
|
||||||
|
stats: b.stats_repo.clone(),
|
||||||
|
diary: b.diary_repo.clone(),
|
||||||
|
social_query: b.social_query.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn returns_profile_with_empty_stats() {
|
async fn returns_profile_with_empty_stats() {
|
||||||
let ctx = TestContextBuilder::new().build();
|
let b = TestContextBuilder::new();
|
||||||
|
let deps = GetProfileDeps {
|
||||||
|
stats: b.stats_repo.clone(),
|
||||||
|
diary: b.diary_repo.clone(),
|
||||||
|
social_query: b.social_query.clone(),
|
||||||
|
};
|
||||||
|
let ctx = b.build();
|
||||||
|
|
||||||
register::execute(
|
register::execute(
|
||||||
&ctx,
|
&ctx,
|
||||||
@@ -28,7 +44,7 @@ async fn returns_profile_with_empty_stats() {
|
|||||||
let uid = user.id().value();
|
let uid = user.id().value();
|
||||||
|
|
||||||
let result = get_profile::execute(
|
let result = get_profile::execute(
|
||||||
&ctx,
|
&deps,
|
||||||
GetUserProfileQuery {
|
GetUserProfileQuery {
|
||||||
user_id: uid,
|
user_id: uid,
|
||||||
view: ProfileView::Recent,
|
view: ProfileView::Recent,
|
||||||
@@ -47,7 +63,13 @@ async fn returns_profile_with_empty_stats() {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn returns_history_view() {
|
async fn returns_history_view() {
|
||||||
let ctx = TestContextBuilder::new().build();
|
let b = TestContextBuilder::new();
|
||||||
|
let deps = GetProfileDeps {
|
||||||
|
stats: b.stats_repo.clone(),
|
||||||
|
diary: b.diary_repo.clone(),
|
||||||
|
social_query: b.social_query.clone(),
|
||||||
|
};
|
||||||
|
let ctx = b.build();
|
||||||
|
|
||||||
register::execute(
|
register::execute(
|
||||||
&ctx,
|
&ctx,
|
||||||
@@ -66,7 +88,7 @@ async fn returns_history_view() {
|
|||||||
let uid = user.id().value();
|
let uid = user.id().value();
|
||||||
|
|
||||||
let result = get_profile::execute(
|
let result = get_profile::execute(
|
||||||
&ctx,
|
&deps,
|
||||||
GetUserProfileQuery {
|
GetUserProfileQuery {
|
||||||
user_id: uid,
|
user_id: uid,
|
||||||
view: ProfileView::History,
|
view: ProfileView::History,
|
||||||
@@ -87,7 +109,13 @@ async fn returns_history_view() {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn returns_trends_view() {
|
async fn returns_trends_view() {
|
||||||
let ctx = TestContextBuilder::new().build();
|
let b = TestContextBuilder::new();
|
||||||
|
let deps = GetProfileDeps {
|
||||||
|
stats: b.stats_repo.clone(),
|
||||||
|
diary: b.diary_repo.clone(),
|
||||||
|
social_query: b.social_query.clone(),
|
||||||
|
};
|
||||||
|
let ctx = b.build();
|
||||||
|
|
||||||
register::execute(
|
register::execute(
|
||||||
&ctx,
|
&ctx,
|
||||||
@@ -106,7 +134,7 @@ async fn returns_trends_view() {
|
|||||||
let uid = user.id().value();
|
let uid = user.id().value();
|
||||||
|
|
||||||
let result = get_profile::execute(
|
let result = get_profile::execute(
|
||||||
&ctx,
|
&deps,
|
||||||
GetUserProfileQuery {
|
GetUserProfileQuery {
|
||||||
user_id: uid,
|
user_id: uid,
|
||||||
view: ProfileView::Trends,
|
view: ProfileView::Trends,
|
||||||
@@ -127,7 +155,13 @@ async fn returns_trends_view() {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn returns_ratings_view() {
|
async fn returns_ratings_view() {
|
||||||
let ctx = TestContextBuilder::new().build();
|
let b = TestContextBuilder::new();
|
||||||
|
let deps = GetProfileDeps {
|
||||||
|
stats: b.stats_repo.clone(),
|
||||||
|
diary: b.diary_repo.clone(),
|
||||||
|
social_query: b.social_query.clone(),
|
||||||
|
};
|
||||||
|
let ctx = b.build();
|
||||||
|
|
||||||
register::execute(
|
register::execute(
|
||||||
&ctx,
|
&ctx,
|
||||||
@@ -146,7 +180,7 @@ async fn returns_ratings_view() {
|
|||||||
let uid = user.id().value();
|
let uid = user.id().value();
|
||||||
|
|
||||||
let result = get_profile::execute(
|
let result = get_profile::execute(
|
||||||
&ctx,
|
&deps,
|
||||||
GetUserProfileQuery {
|
GetUserProfileQuery {
|
||||||
user_id: uid,
|
user_id: uid,
|
||||||
view: ProfileView::Ratings,
|
view: ProfileView::Ratings,
|
||||||
@@ -165,7 +199,13 @@ async fn returns_ratings_view() {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn returns_recent_with_search() {
|
async fn returns_recent_with_search() {
|
||||||
let ctx = TestContextBuilder::new().build();
|
let b = TestContextBuilder::new();
|
||||||
|
let deps = GetProfileDeps {
|
||||||
|
stats: b.stats_repo.clone(),
|
||||||
|
diary: b.diary_repo.clone(),
|
||||||
|
social_query: b.social_query.clone(),
|
||||||
|
};
|
||||||
|
let ctx = b.build();
|
||||||
|
|
||||||
register::execute(
|
register::execute(
|
||||||
&ctx,
|
&ctx,
|
||||||
@@ -184,7 +224,7 @@ async fn returns_recent_with_search() {
|
|||||||
let uid = user.id().value();
|
let uid = user.id().value();
|
||||||
|
|
||||||
let result = get_profile::execute(
|
let result = get_profile::execute(
|
||||||
&ctx,
|
&deps,
|
||||||
GetUserProfileQuery {
|
GetUserProfileQuery {
|
||||||
user_id: uid,
|
user_id: uid,
|
||||||
view: ProfileView::Recent,
|
view: ProfileView::Recent,
|
||||||
@@ -203,7 +243,13 @@ async fn returns_recent_with_search() {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn non_own_profile_skips_pending_followers() {
|
async fn non_own_profile_skips_pending_followers() {
|
||||||
let ctx = TestContextBuilder::new().build();
|
let b = TestContextBuilder::new();
|
||||||
|
let deps = GetProfileDeps {
|
||||||
|
stats: b.stats_repo.clone(),
|
||||||
|
diary: b.diary_repo.clone(),
|
||||||
|
social_query: b.social_query.clone(),
|
||||||
|
};
|
||||||
|
let ctx = b.build();
|
||||||
|
|
||||||
register::execute(
|
register::execute(
|
||||||
&ctx,
|
&ctx,
|
||||||
@@ -222,7 +268,7 @@ async fn non_own_profile_skips_pending_followers() {
|
|||||||
let uid = user.id().value();
|
let uid = user.id().value();
|
||||||
|
|
||||||
let result = get_profile::execute(
|
let result = get_profile::execute(
|
||||||
&ctx,
|
&deps,
|
||||||
GetUserProfileQuery {
|
GetUserProfileQuery {
|
||||||
user_id: uid,
|
user_id: uid,
|
||||||
view: ProfileView::Recent,
|
view: ProfileView::Recent,
|
||||||
|
|||||||
@@ -4,9 +4,10 @@ use crate::{test_helpers::TestContextBuilder, users::get_settings};
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn returns_default_settings() {
|
async fn returns_default_settings() {
|
||||||
let ctx = TestContextBuilder::new().build();
|
let b = TestContextBuilder::new();
|
||||||
|
let user_settings = b.user_settings_repo.clone();
|
||||||
|
|
||||||
let settings = get_settings::execute(&ctx, Uuid::nil()).await.unwrap();
|
let settings = get_settings::execute(user_settings, Uuid::nil()).await.unwrap();
|
||||||
|
|
||||||
assert!(!settings.federate_goals());
|
assert!(!settings.federate_goals());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,9 +4,11 @@ use crate::users::queries::GetUsersQuery;
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn returns_empty_when_no_users() {
|
async fn returns_empty_when_no_users() {
|
||||||
let ctx = TestContextBuilder::new().build();
|
let b = TestContextBuilder::new();
|
||||||
|
let user = b.user_repo.clone();
|
||||||
|
let social_query = b.social_query.clone();
|
||||||
|
|
||||||
let result = get_users::execute(&ctx, GetUsersQuery).await.unwrap();
|
let result = get_users::execute(user, social_query, GetUsersQuery).await.unwrap();
|
||||||
|
|
||||||
assert!(result.users.is_empty());
|
assert!(result.users.is_empty());
|
||||||
assert!(result.remote_actors.is_empty());
|
assert!(result.remote_actors.is_empty());
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ use uuid::Uuid;
|
|||||||
use crate::{
|
use crate::{
|
||||||
auth::{commands::RegisterCommand, register},
|
auth::{commands::RegisterCommand, register},
|
||||||
test_helpers::TestContextBuilder,
|
test_helpers::TestContextBuilder,
|
||||||
users::{commands::UpdateProfileCommand, update_profile},
|
users::{commands::UpdateProfileCommand, deps::UpdateProfileDeps, update_profile},
|
||||||
};
|
};
|
||||||
|
|
||||||
async fn register_user(
|
async fn register_user(
|
||||||
@@ -40,15 +40,20 @@ async fn register_user(
|
|||||||
async fn updates_display_name() {
|
async fn updates_display_name() {
|
||||||
let users = InMemoryUserRepository::new();
|
let users = InMemoryUserRepository::new();
|
||||||
let events = NoopEventPublisher::new();
|
let events = NoopEventPublisher::new();
|
||||||
let ctx = TestContextBuilder::new()
|
let b = TestContextBuilder::new()
|
||||||
.with_users(Arc::clone(&users) as _)
|
.with_users(Arc::clone(&users) as _)
|
||||||
.with_event_publisher(Arc::clone(&events) as _)
|
.with_event_publisher(Arc::clone(&events) as _);
|
||||||
.build();
|
let deps = UpdateProfileDeps {
|
||||||
|
user: b.user_repo.clone(),
|
||||||
|
object_storage: b.object_storage.clone(),
|
||||||
|
event_publisher: b.event_publisher.clone(),
|
||||||
|
};
|
||||||
|
let ctx = b.build();
|
||||||
|
|
||||||
let uid = register_user(&ctx, &users).await;
|
let uid = register_user(&ctx, &users).await;
|
||||||
|
|
||||||
update_profile::execute(
|
update_profile::execute(
|
||||||
&ctx,
|
&deps,
|
||||||
UpdateProfileCommand {
|
UpdateProfileCommand {
|
||||||
user_id: uid,
|
user_id: uid,
|
||||||
display_name: Some("Alice W.".into()),
|
display_name: Some("Alice W.".into()),
|
||||||
@@ -74,14 +79,18 @@ async fn updates_display_name() {
|
|||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn rejects_invalid_avatar_content_type() {
|
async fn rejects_invalid_avatar_content_type() {
|
||||||
let users = InMemoryUserRepository::new();
|
let users = InMemoryUserRepository::new();
|
||||||
let ctx = TestContextBuilder::new()
|
let b = TestContextBuilder::new().with_users(Arc::clone(&users) as _);
|
||||||
.with_users(Arc::clone(&users) as _)
|
let deps = UpdateProfileDeps {
|
||||||
.build();
|
user: b.user_repo.clone(),
|
||||||
|
object_storage: b.object_storage.clone(),
|
||||||
|
event_publisher: b.event_publisher.clone(),
|
||||||
|
};
|
||||||
|
let ctx = b.build();
|
||||||
|
|
||||||
let uid = register_user(&ctx, &users).await;
|
let uid = register_user(&ctx, &users).await;
|
||||||
|
|
||||||
let result = update_profile::execute(
|
let result = update_profile::execute(
|
||||||
&ctx,
|
&deps,
|
||||||
UpdateProfileCommand {
|
UpdateProfileCommand {
|
||||||
user_id: uid,
|
user_id: uid,
|
||||||
display_name: None,
|
display_name: None,
|
||||||
@@ -102,15 +111,20 @@ async fn rejects_invalid_avatar_content_type() {
|
|||||||
async fn uploads_avatar() {
|
async fn uploads_avatar() {
|
||||||
let users = InMemoryUserRepository::new();
|
let users = InMemoryUserRepository::new();
|
||||||
let events = NoopEventPublisher::new();
|
let events = NoopEventPublisher::new();
|
||||||
let ctx = TestContextBuilder::new()
|
let b = TestContextBuilder::new()
|
||||||
.with_users(Arc::clone(&users) as _)
|
.with_users(Arc::clone(&users) as _)
|
||||||
.with_event_publisher(Arc::clone(&events) as _)
|
.with_event_publisher(Arc::clone(&events) as _);
|
||||||
.build();
|
let deps = UpdateProfileDeps {
|
||||||
|
user: b.user_repo.clone(),
|
||||||
|
object_storage: b.object_storage.clone(),
|
||||||
|
event_publisher: b.event_publisher.clone(),
|
||||||
|
};
|
||||||
|
let ctx = b.build();
|
||||||
|
|
||||||
let uid = register_user(&ctx, &users).await;
|
let uid = register_user(&ctx, &users).await;
|
||||||
|
|
||||||
update_profile::execute(
|
update_profile::execute(
|
||||||
&ctx,
|
&deps,
|
||||||
UpdateProfileCommand {
|
UpdateProfileCommand {
|
||||||
user_id: uid,
|
user_id: uid,
|
||||||
display_name: None,
|
display_name: None,
|
||||||
@@ -142,15 +156,20 @@ async fn uploads_avatar() {
|
|||||||
async fn uploads_banner() {
|
async fn uploads_banner() {
|
||||||
let users = InMemoryUserRepository::new();
|
let users = InMemoryUserRepository::new();
|
||||||
let events = NoopEventPublisher::new();
|
let events = NoopEventPublisher::new();
|
||||||
let ctx = TestContextBuilder::new()
|
let b = TestContextBuilder::new()
|
||||||
.with_users(Arc::clone(&users) as _)
|
.with_users(Arc::clone(&users) as _)
|
||||||
.with_event_publisher(Arc::clone(&events) as _)
|
.with_event_publisher(Arc::clone(&events) as _);
|
||||||
.build();
|
let deps = UpdateProfileDeps {
|
||||||
|
user: b.user_repo.clone(),
|
||||||
|
object_storage: b.object_storage.clone(),
|
||||||
|
event_publisher: b.event_publisher.clone(),
|
||||||
|
};
|
||||||
|
let ctx = b.build();
|
||||||
|
|
||||||
let uid = register_user(&ctx, &users).await;
|
let uid = register_user(&ctx, &users).await;
|
||||||
|
|
||||||
update_profile::execute(
|
update_profile::execute(
|
||||||
&ctx,
|
&deps,
|
||||||
UpdateProfileCommand {
|
UpdateProfileCommand {
|
||||||
user_id: uid,
|
user_id: uid,
|
||||||
display_name: None,
|
display_name: None,
|
||||||
@@ -180,10 +199,16 @@ async fn uploads_banner() {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn fails_for_nonexistent_user() {
|
async fn fails_for_nonexistent_user() {
|
||||||
let ctx = TestContextBuilder::new().build();
|
let b = TestContextBuilder::new();
|
||||||
|
let deps = UpdateProfileDeps {
|
||||||
|
user: b.user_repo.clone(),
|
||||||
|
object_storage: b.object_storage.clone(),
|
||||||
|
event_publisher: b.event_publisher.clone(),
|
||||||
|
};
|
||||||
|
let _ctx = b.build();
|
||||||
|
|
||||||
let result = update_profile::execute(
|
let result = update_profile::execute(
|
||||||
&ctx,
|
&deps,
|
||||||
UpdateProfileCommand {
|
UpdateProfileCommand {
|
||||||
user_id: Uuid::new_v4(),
|
user_id: Uuid::new_v4(),
|
||||||
display_name: Some("Ghost".into()),
|
display_name: Some("Ghost".into()),
|
||||||
@@ -203,14 +228,18 @@ async fn fails_for_nonexistent_user() {
|
|||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn rejects_invalid_banner_content_type() {
|
async fn rejects_invalid_banner_content_type() {
|
||||||
let users = InMemoryUserRepository::new();
|
let users = InMemoryUserRepository::new();
|
||||||
let ctx = TestContextBuilder::new()
|
let b = TestContextBuilder::new().with_users(Arc::clone(&users) as _);
|
||||||
.with_users(Arc::clone(&users) as _)
|
let deps = UpdateProfileDeps {
|
||||||
.build();
|
user: b.user_repo.clone(),
|
||||||
|
object_storage: b.object_storage.clone(),
|
||||||
|
event_publisher: b.event_publisher.clone(),
|
||||||
|
};
|
||||||
|
let ctx = b.build();
|
||||||
|
|
||||||
let uid = register_user(&ctx, &users).await;
|
let uid = register_user(&ctx, &users).await;
|
||||||
|
|
||||||
let result = update_profile::execute(
|
let result = update_profile::execute(
|
||||||
&ctx,
|
&deps,
|
||||||
UpdateProfileCommand {
|
UpdateProfileCommand {
|
||||||
user_id: uid,
|
user_id: uid,
|
||||||
display_name: None,
|
display_name: None,
|
||||||
@@ -231,15 +260,20 @@ async fn rejects_invalid_banner_content_type() {
|
|||||||
async fn text_only_update_emits_user_updated_no_image_stored() {
|
async fn text_only_update_emits_user_updated_no_image_stored() {
|
||||||
let users = InMemoryUserRepository::new();
|
let users = InMemoryUserRepository::new();
|
||||||
let events = NoopEventPublisher::new();
|
let events = NoopEventPublisher::new();
|
||||||
let ctx = TestContextBuilder::new()
|
let b = TestContextBuilder::new()
|
||||||
.with_users(Arc::clone(&users) as _)
|
.with_users(Arc::clone(&users) as _)
|
||||||
.with_event_publisher(Arc::clone(&events) as _)
|
.with_event_publisher(Arc::clone(&events) as _);
|
||||||
.build();
|
let deps = UpdateProfileDeps {
|
||||||
|
user: b.user_repo.clone(),
|
||||||
|
object_storage: b.object_storage.clone(),
|
||||||
|
event_publisher: b.event_publisher.clone(),
|
||||||
|
};
|
||||||
|
let ctx = b.build();
|
||||||
|
|
||||||
let uid = register_user(&ctx, &users).await;
|
let uid = register_user(&ctx, &users).await;
|
||||||
|
|
||||||
update_profile::execute(
|
update_profile::execute(
|
||||||
&ctx,
|
&deps,
|
||||||
UpdateProfileCommand {
|
UpdateProfileCommand {
|
||||||
user_id: uid,
|
user_id: uid,
|
||||||
display_name: Some("Alice Updated".into()),
|
display_name: Some("Alice Updated".into()),
|
||||||
|
|||||||
@@ -14,13 +14,15 @@ use crate::{
|
|||||||
async fn saves_profile_fields() {
|
async fn saves_profile_fields() {
|
||||||
let fields_repo = InMemoryProfileFieldsRepo::new();
|
let fields_repo = InMemoryProfileFieldsRepo::new();
|
||||||
let events = NoopEventPublisher::new();
|
let events = NoopEventPublisher::new();
|
||||||
let ctx = TestContextBuilder::new()
|
let b = TestContextBuilder::new()
|
||||||
.with_profile_fields(Arc::clone(&fields_repo) as _)
|
.with_profile_fields(Arc::clone(&fields_repo) as _)
|
||||||
.with_event_publisher(Arc::clone(&events) as _)
|
.with_event_publisher(Arc::clone(&events) as _);
|
||||||
.build();
|
let profile_fields = b.profile_fields_repo.clone();
|
||||||
|
let event_publisher = b.event_publisher.clone();
|
||||||
|
|
||||||
update_profile_fields::execute(
|
update_profile_fields::execute(
|
||||||
&ctx,
|
profile_fields,
|
||||||
|
event_publisher,
|
||||||
UpdateProfileFieldsCommand {
|
UpdateProfileFieldsCommand {
|
||||||
user_id: Uuid::nil(),
|
user_id: Uuid::nil(),
|
||||||
fields: vec![
|
fields: vec![
|
||||||
@@ -48,7 +50,9 @@ async fn saves_profile_fields() {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn rejects_more_than_four_fields() {
|
async fn rejects_more_than_four_fields() {
|
||||||
let ctx = TestContextBuilder::new().build();
|
let b = TestContextBuilder::new();
|
||||||
|
let profile_fields = b.profile_fields_repo.clone();
|
||||||
|
let event_publisher = b.event_publisher.clone();
|
||||||
|
|
||||||
let fields: Vec<ProfileField> = (0..5)
|
let fields: Vec<ProfileField> = (0..5)
|
||||||
.map(|i| ProfileField {
|
.map(|i| ProfileField {
|
||||||
@@ -58,7 +62,8 @@ async fn rejects_more_than_four_fields() {
|
|||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let result = update_profile_fields::execute(
|
let result = update_profile_fields::execute(
|
||||||
&ctx,
|
profile_fields,
|
||||||
|
event_publisher,
|
||||||
UpdateProfileFieldsCommand {
|
UpdateProfileFieldsCommand {
|
||||||
user_id: Uuid::nil(),
|
user_id: Uuid::nil(),
|
||||||
fields,
|
fields,
|
||||||
|
|||||||
@@ -11,14 +11,14 @@ use crate::{
|
|||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn updates_federate_goals() {
|
async fn updates_federate_goals() {
|
||||||
let settings_repo = InMemoryUserSettingsRepository::new();
|
let settings_repo = InMemoryUserSettingsRepository::new();
|
||||||
let ctx = TestContextBuilder::new()
|
let b = TestContextBuilder::new()
|
||||||
.with_user_settings(Arc::clone(&settings_repo) as _)
|
.with_user_settings(Arc::clone(&settings_repo) as _);
|
||||||
.build();
|
let user_settings = b.user_settings_repo.clone();
|
||||||
|
|
||||||
let uid = Uuid::nil();
|
let uid = Uuid::nil();
|
||||||
|
|
||||||
crate::users::update_settings::execute(
|
crate::users::update_settings::execute(
|
||||||
&ctx,
|
user_settings.clone(),
|
||||||
UpdateUserSettingsCommand {
|
UpdateUserSettingsCommand {
|
||||||
user_id: uid,
|
user_id: uid,
|
||||||
federate_goals: true,
|
federate_goals: true,
|
||||||
@@ -27,6 +27,6 @@ async fn updates_federate_goals() {
|
|||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let settings = get_settings::execute(&ctx, uid).await.unwrap();
|
let settings = get_settings::execute(user_settings, uid).await.unwrap();
|
||||||
assert!(settings.federate_goals());
|
assert!(settings.federate_goals());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,11 @@
|
|||||||
use domain::{errors::DomainError, events::DomainEvent, value_objects::UserId};
|
use domain::{errors::DomainError, events::DomainEvent, value_objects::UserId};
|
||||||
|
|
||||||
use crate::{context::AppContext, users::commands::UpdateProfileCommand};
|
use crate::users::{commands::UpdateProfileCommand, deps::UpdateProfileDeps};
|
||||||
|
|
||||||
pub async fn execute(ctx: &AppContext, cmd: UpdateProfileCommand) -> Result<(), DomainError> {
|
pub async fn execute(deps: &UpdateProfileDeps, cmd: UpdateProfileCommand) -> Result<(), DomainError> {
|
||||||
let user_id = UserId::from_uuid(cmd.user_id);
|
let user_id = UserId::from_uuid(cmd.user_id);
|
||||||
|
|
||||||
let user = ctx
|
let user = deps
|
||||||
.repos
|
|
||||||
.user
|
.user
|
||||||
.find_by_id(&user_id)
|
.find_by_id(&user_id)
|
||||||
.await?
|
.await?
|
||||||
@@ -21,12 +20,11 @@ pub async fn execute(ctx: &AppContext, cmd: UpdateProfileCommand) -> Result<(),
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
if let Some(old_path) = user.avatar_path() {
|
if let Some(old_path) = user.avatar_path() {
|
||||||
let _ = ctx.services.object_storage.delete(old_path).await;
|
let _ = deps.object_storage.delete(old_path).await;
|
||||||
}
|
}
|
||||||
let key = format!("avatars/{}", user_id.value());
|
let key = format!("avatars/{}", user_id.value());
|
||||||
let stored = ctx.services.object_storage.store(&key, &bytes).await?;
|
let stored = deps.object_storage.store(&key, &bytes).await?;
|
||||||
if let Err(e) = ctx
|
if let Err(e) = deps
|
||||||
.services
|
|
||||||
.event_publisher
|
.event_publisher
|
||||||
.publish(&DomainEvent::ImageStored {
|
.publish(&DomainEvent::ImageStored {
|
||||||
key: stored.clone(),
|
key: stored.clone(),
|
||||||
@@ -49,12 +47,11 @@ pub async fn execute(ctx: &AppContext, cmd: UpdateProfileCommand) -> Result<(),
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
if let Some(old_path) = user.banner_path() {
|
if let Some(old_path) = user.banner_path() {
|
||||||
let _ = ctx.services.object_storage.delete(old_path).await;
|
let _ = deps.object_storage.delete(old_path).await;
|
||||||
}
|
}
|
||||||
let key = format!("banners/{}", user_id.value());
|
let key = format!("banners/{}", user_id.value());
|
||||||
let stored = ctx.services.object_storage.store(&key, &bytes).await?;
|
let stored = deps.object_storage.store(&key, &bytes).await?;
|
||||||
if let Err(e) = ctx
|
if let Err(e) = deps
|
||||||
.services
|
|
||||||
.event_publisher
|
.event_publisher
|
||||||
.publish(&DomainEvent::ImageStored {
|
.publish(&DomainEvent::ImageStored {
|
||||||
key: stored.clone(),
|
key: stored.clone(),
|
||||||
@@ -68,8 +65,7 @@ pub async fn execute(ctx: &AppContext, cmd: UpdateProfileCommand) -> Result<(),
|
|||||||
user.banner_path().map(|s| s.to_string())
|
user.banner_path().map(|s| s.to_string())
|
||||||
};
|
};
|
||||||
|
|
||||||
ctx.repos
|
deps.user
|
||||||
.user
|
|
||||||
.update_profile(
|
.update_profile(
|
||||||
&user_id,
|
&user_id,
|
||||||
&domain::models::UserProfile {
|
&domain::models::UserProfile {
|
||||||
@@ -83,8 +79,7 @@ pub async fn execute(ctx: &AppContext, cmd: UpdateProfileCommand) -> Result<(),
|
|||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
ctx.services
|
deps.event_publisher
|
||||||
.event_publisher
|
|
||||||
.publish(&DomainEvent::UserUpdated { user_id })
|
.publish(&DomainEvent::UserUpdated { user_id })
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
|||||||
@@ -1,18 +1,20 @@
|
|||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
use domain::{
|
use domain::{
|
||||||
errors::DomainError, events::DomainEvent, models::UserProfile, value_objects::UserId,
|
errors::DomainError, events::DomainEvent, models::UserProfile, ports::{EventPublisher, UserProfileFieldsRepository}, value_objects::UserId,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{context::AppContext, users::commands::UpdateProfileFieldsCommand};
|
use crate::users::commands::UpdateProfileFieldsCommand;
|
||||||
|
|
||||||
pub async fn execute(ctx: &AppContext, cmd: UpdateProfileFieldsCommand) -> Result<(), DomainError> {
|
pub async fn execute(
|
||||||
|
profile_fields: Arc<dyn UserProfileFieldsRepository>,
|
||||||
|
event_publisher: Arc<dyn EventPublisher>,
|
||||||
|
cmd: UpdateProfileFieldsCommand,
|
||||||
|
) -> Result<(), DomainError> {
|
||||||
UserProfile::validate_custom_fields(&cmd.fields)?;
|
UserProfile::validate_custom_fields(&cmd.fields)?;
|
||||||
let user_id = UserId::from_uuid(cmd.user_id);
|
let user_id = UserId::from_uuid(cmd.user_id);
|
||||||
ctx.repos
|
profile_fields.set_fields(&user_id, cmd.fields).await?;
|
||||||
.profile_fields
|
event_publisher
|
||||||
.set_fields(&user_id, cmd.fields)
|
|
||||||
.await?;
|
|
||||||
ctx.services
|
|
||||||
.event_publisher
|
|
||||||
.publish(&DomainEvent::UserUpdated { user_id })
|
.publish(&DomainEvent::UserUpdated { user_id })
|
||||||
.await?;
|
.await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
@@ -1,17 +1,20 @@
|
|||||||
use domain::{errors::DomainError, value_objects::UserId};
|
use std::sync::Arc;
|
||||||
|
|
||||||
use crate::context::AppContext;
|
use domain::{errors::DomainError, ports::UserSettingsRepository, value_objects::UserId};
|
||||||
|
|
||||||
pub struct UpdateUserSettingsCommand {
|
pub struct UpdateUserSettingsCommand {
|
||||||
pub user_id: uuid::Uuid,
|
pub user_id: uuid::Uuid,
|
||||||
pub federate_goals: bool,
|
pub federate_goals: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn execute(ctx: &AppContext, cmd: UpdateUserSettingsCommand) -> Result<(), DomainError> {
|
pub async fn execute(
|
||||||
|
user_settings: Arc<dyn UserSettingsRepository>,
|
||||||
|
cmd: UpdateUserSettingsCommand,
|
||||||
|
) -> Result<(), DomainError> {
|
||||||
let uid = UserId::from_uuid(cmd.user_id);
|
let uid = UserId::from_uuid(cmd.user_id);
|
||||||
let mut settings = ctx.repos.user_settings.get(&uid).await?;
|
let mut settings = user_settings.get(&uid).await?;
|
||||||
settings.set_federate_goals(cmd.federate_goals);
|
settings.set_federate_goals(cmd.federate_goals);
|
||||||
ctx.repos.user_settings.save(&settings).await
|
user_settings.save(&settings).await
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|||||||
@@ -169,8 +169,11 @@ pub async fn get_settings(
|
|||||||
State(state): State<AppState>,
|
State(state): State<AppState>,
|
||||||
user: AuthenticatedUser,
|
user: AuthenticatedUser,
|
||||||
) -> Result<Json<UserSettingsDto>, ApiError> {
|
) -> Result<Json<UserSettingsDto>, ApiError> {
|
||||||
let settings =
|
let settings = application::users::get_settings::execute(
|
||||||
application::users::get_settings::execute(&state.app_ctx, user.0.value()).await?;
|
state.app_ctx.repos.user_settings.clone(),
|
||||||
|
user.0.value(),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
Ok(Json(UserSettingsDto {
|
Ok(Json(UserSettingsDto {
|
||||||
federate_goals: settings.federate_goals(),
|
federate_goals: settings.federate_goals(),
|
||||||
}))
|
}))
|
||||||
@@ -191,7 +194,7 @@ pub async fn update_settings(
|
|||||||
Json(req): Json<UpdateUserSettingsRequest>,
|
Json(req): Json<UpdateUserSettingsRequest>,
|
||||||
) -> Result<StatusCode, ApiError> {
|
) -> Result<StatusCode, ApiError> {
|
||||||
application::users::update_settings::execute(
|
application::users::update_settings::execute(
|
||||||
&state.app_ctx,
|
state.app_ctx.repos.user_settings.clone(),
|
||||||
application::users::update_settings::UpdateUserSettingsCommand {
|
application::users::update_settings::UpdateUserSettingsCommand {
|
||||||
user_id: user.0.value(),
|
user_id: user.0.value(),
|
||||||
federate_goals: req.federate_goals,
|
federate_goals: req.federate_goals,
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ use axum::{
|
|||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
use application::users::{
|
use application::users::{
|
||||||
|
deps::{GetProfileDeps, UpdateProfileDeps},
|
||||||
get_profile as get_user_profile_uc, get_users,
|
get_profile as get_user_profile_uc, get_users,
|
||||||
queries::{GetUserProfileQuery, GetUsersQuery},
|
queries::{GetUserProfileQuery, GetUsersQuery},
|
||||||
update_profile, update_profile_fields,
|
update_profile, update_profile_fields,
|
||||||
@@ -52,7 +53,7 @@ pub async fn get_profile(
|
|||||||
AuthenticatedUser(user_id): AuthenticatedUser,
|
AuthenticatedUser(user_id): AuthenticatedUser,
|
||||||
) -> Result<Json<ProfileResponse>, ApiError> {
|
) -> Result<Json<ProfileResponse>, ApiError> {
|
||||||
let profile = application::users::get_current_profile::execute(
|
let profile = application::users::get_current_profile::execute(
|
||||||
&state.app_ctx,
|
state.app_ctx.repos.user.clone(),
|
||||||
application::users::queries::GetCurrentProfileQuery {
|
application::users::queries::GetCurrentProfileQuery {
|
||||||
user_id: user_id.value(),
|
user_id: user_id.value(),
|
||||||
},
|
},
|
||||||
@@ -156,7 +157,12 @@ pub async fn update_profile_handler(
|
|||||||
also_known_as,
|
also_known_as,
|
||||||
};
|
};
|
||||||
|
|
||||||
match update_profile::execute(&state.app_ctx, cmd).await {
|
let deps = UpdateProfileDeps {
|
||||||
|
user: state.app_ctx.repos.user.clone(),
|
||||||
|
object_storage: state.app_ctx.services.object_storage.clone(),
|
||||||
|
event_publisher: state.app_ctx.services.event_publisher.clone(),
|
||||||
|
};
|
||||||
|
match update_profile::execute(&deps, cmd).await {
|
||||||
Ok(()) => StatusCode::NO_CONTENT.into_response(),
|
Ok(()) => StatusCode::NO_CONTENT.into_response(),
|
||||||
Err(e) => crate::errors::domain_error_response(e),
|
Err(e) => crate::errors::domain_error_response(e),
|
||||||
}
|
}
|
||||||
@@ -197,7 +203,13 @@ pub async fn update_profile_fields_handler(
|
|||||||
fields,
|
fields,
|
||||||
};
|
};
|
||||||
|
|
||||||
match update_profile_fields::execute(&state.app_ctx, cmd).await {
|
match update_profile_fields::execute(
|
||||||
|
state.app_ctx.repos.profile_fields.clone(),
|
||||||
|
state.app_ctx.services.event_publisher.clone(),
|
||||||
|
cmd,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
{
|
||||||
Ok(()) => StatusCode::NO_CONTENT.into_response(),
|
Ok(()) => StatusCode::NO_CONTENT.into_response(),
|
||||||
Err(e) => crate::errors::domain_error_response(e),
|
Err(e) => crate::errors::domain_error_response(e),
|
||||||
}
|
}
|
||||||
@@ -208,7 +220,12 @@ pub async fn update_profile_fields_handler(
|
|||||||
responses((status = 200, body = UsersResponse)),
|
responses((status = 200, body = UsersResponse)),
|
||||||
)]
|
)]
|
||||||
pub async fn list_users(State(state): State<AppState>) -> Result<Json<UsersResponse>, ApiError> {
|
pub async fn list_users(State(state): State<AppState>) -> Result<Json<UsersResponse>, ApiError> {
|
||||||
let result = get_users::execute(&state.app_ctx, GetUsersQuery).await?;
|
let result = get_users::execute(
|
||||||
|
state.app_ctx.repos.user.clone(),
|
||||||
|
state.app_ctx.repos.social_query.clone(),
|
||||||
|
GetUsersQuery,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
Ok(Json(UsersResponse {
|
Ok(Json(UsersResponse {
|
||||||
users: result
|
users: result
|
||||||
.users
|
.users
|
||||||
@@ -262,8 +279,13 @@ pub async fn get_user_profile(
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let get_profile_deps = GetProfileDeps {
|
||||||
|
stats: state.app_ctx.repos.stats.clone(),
|
||||||
|
diary: state.app_ctx.repos.diary.clone(),
|
||||||
|
social_query: state.app_ctx.repos.social_query.clone(),
|
||||||
|
};
|
||||||
let profile = match get_user_profile_uc::execute(
|
let profile = match get_user_profile_uc::execute(
|
||||||
&state.app_ctx,
|
&get_profile_deps,
|
||||||
GetUserProfileQuery {
|
GetUserProfileQuery {
|
||||||
user_id,
|
user_id,
|
||||||
view: profile_view,
|
view: profile_view,
|
||||||
@@ -378,7 +400,8 @@ pub async fn get_users_list(
|
|||||||
ctx.canonical_url = format!("{}/users", state.app_ctx.config.base_url);
|
ctx.canonical_url = format!("{}/users", state.app_ctx.config.base_url);
|
||||||
|
|
||||||
match application::users::get_users::execute(
|
match application::users::get_users::execute(
|
||||||
&state.app_ctx,
|
state.app_ctx.repos.user.clone(),
|
||||||
|
state.app_ctx.repos.social_query.clone(),
|
||||||
application::users::queries::GetUsersQuery,
|
application::users::queries::GetUsersQuery,
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
@@ -517,7 +540,12 @@ pub async fn get_user_profile_html(
|
|||||||
is_own_profile,
|
is_own_profile,
|
||||||
};
|
};
|
||||||
|
|
||||||
match application::users::get_profile::execute(&state.app_ctx, query).await {
|
let html_profile_deps = GetProfileDeps {
|
||||||
|
stats: state.app_ctx.repos.stats.clone(),
|
||||||
|
diary: state.app_ctx.repos.diary.clone(),
|
||||||
|
social_query: state.app_ctx.repos.social_query.clone(),
|
||||||
|
};
|
||||||
|
match application::users::get_profile::execute(&html_profile_deps, query).await {
|
||||||
Ok(profile) => {
|
Ok(profile) => {
|
||||||
let (offset, has_more, limit) = profile
|
let (offset, has_more, limit) = profile
|
||||||
.entries
|
.entries
|
||||||
@@ -805,7 +833,12 @@ pub async fn post_profile_settings(
|
|||||||
banner_content_type,
|
banner_content_type,
|
||||||
also_known_as,
|
also_known_as,
|
||||||
};
|
};
|
||||||
let _ = update_profile::execute(&state.app_ctx, cmd).await;
|
let update_deps = UpdateProfileDeps {
|
||||||
|
user: state.app_ctx.repos.user.clone(),
|
||||||
|
object_storage: state.app_ctx.services.object_storage.clone(),
|
||||||
|
event_publisher: state.app_ctx.services.event_publisher.clone(),
|
||||||
|
};
|
||||||
|
let _ = update_profile::execute(&update_deps, cmd).await;
|
||||||
|
|
||||||
let fields: Vec<domain::models::ProfileField> = (0..4)
|
let fields: Vec<domain::models::ProfileField> = (0..4)
|
||||||
.filter_map(|i| {
|
.filter_map(|i| {
|
||||||
@@ -822,7 +855,12 @@ pub async fn post_profile_settings(
|
|||||||
user_id: user_id.value(),
|
user_id: user_id.value(),
|
||||||
fields,
|
fields,
|
||||||
};
|
};
|
||||||
let _ = update_profile_fields::execute(&state.app_ctx, fields_cmd).await;
|
let _ = update_profile_fields::execute(
|
||||||
|
state.app_ctx.repos.profile_fields.clone(),
|
||||||
|
state.app_ctx.services.event_publisher.clone(),
|
||||||
|
fields_cmd,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
|
||||||
axum::response::Redirect::to("/settings/profile?saved=1").into_response()
|
axum::response::Redirect::to("/settings/profile?saved=1").into_response()
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user