use models::users::user; use models::users::{user_blocks, user_followers}; use sea_orm::{ActiveModelTrait, ColumnTrait, EntityTrait, QueryFilter, Set}; use time::OffsetDateTime; use uuid::Uuid; use super::AuthService; use crate::errors::AuthError; use crate::share::types::UserPublic; impl AuthService { pub async fn public_user(&self, uid: Uuid) -> Result { let Some(user) = user::Entity::find_by_id(uid).one(self.db().read()).await? else { return Err(AuthError::NotFound); }; Ok(UserPublic { uid: user.uid, username: user.username, display_name: user.display_name, avatar_url: user.avatar_url, }) } pub async fn follow(&self, follower_uid: Uuid, followed_uid: Uuid) -> Result<(), AuthError> { if follower_uid == followed_uid { return Err(AuthError::BadRequest( "cannot follow yourself".to_string(), )); } let db = self.db(); let followed_exists = user::Entity::find_by_id(followed_uid).one(db.read()).await?; if followed_exists.is_none() { return Err(AuthError::NotFound); } let existing = user_followers::Entity::find() .filter(user_followers::Column::FollowerId.eq(follower_uid)) .filter(user_followers::Column::FollowedId.eq(followed_uid)) .one(db.write()) .await?; if existing.is_some() { return Ok(()); } let row = user_followers::ActiveModel { id: Set(Uuid::now_v7()), follower_id: Set(follower_uid), followed_id: Set(followed_uid), created_at: Set(OffsetDateTime::now_utc()), }; row.insert(db.write()).await?; Ok(()) } pub async fn unfollow(&self, follower_uid: Uuid, followed_uid: Uuid) -> Result<(), AuthError> { let db = self.db(); user_followers::Entity::delete_many() .filter(user_followers::Column::FollowerId.eq(follower_uid)) .filter(user_followers::Column::FollowedId.eq(followed_uid)) .exec(db.write()) .await?; Ok(()) } pub async fn followers(&self, uid: Uuid) -> Result, AuthError> { let rows = user_followers::Entity::find() .filter(user_followers::Column::FollowedId.eq(uid)) .all(self.db().read()) .await?; let ids: Vec = rows.into_iter().map(|row| row.follower_id).collect(); self.load_users_public(&ids).await } pub async fn following(&self, uid: Uuid) -> Result, AuthError> { let rows = user_followers::Entity::find() .filter(user_followers::Column::FollowerId.eq(uid)) .all(self.db().read()) .await?; let ids: Vec = rows.into_iter().map(|row| row.followed_id).collect(); self.load_users_public(&ids).await } pub async fn block(&self, blocker_uid: Uuid, blocked_uid: Uuid) -> Result<(), AuthError> { if blocker_uid == blocked_uid { return Err(AuthError::BadRequest("cannot block yourself".to_string())); } let db = self.db(); let blocked_exists = user::Entity::find_by_id(blocked_uid).one(db.read()).await?; if blocked_exists.is_none() { return Err(AuthError::NotFound); } let existing = user_blocks::Entity::find() .filter(user_blocks::Column::BlockerId.eq(blocker_uid)) .filter(user_blocks::Column::BlockedId.eq(blocked_uid)) .one(db.write()) .await?; if existing.is_some() { return Ok(()); } let row = user_blocks::ActiveModel { id: Set(Uuid::now_v7()), blocker_id: Set(blocker_uid), blocked_id: Set(blocked_uid), created_at: Set(OffsetDateTime::now_utc()), }; row.insert(db.write()).await?; Ok(()) } pub async fn unblock(&self, blocker_uid: Uuid, blocked_uid: Uuid) -> Result<(), AuthError> { let db = self.db(); user_blocks::Entity::delete_many() .filter(user_blocks::Column::BlockerId.eq(blocker_uid)) .filter(user_blocks::Column::BlockedId.eq(blocked_uid)) .exec(db.write()) .await?; Ok(()) } pub async fn blocked_users(&self, uid: Uuid) -> Result, AuthError> { let rows = user_blocks::Entity::find() .filter(user_blocks::Column::BlockerId.eq(uid)) .all(self.db().read()) .await?; let ids: Vec = rows.into_iter().map(|row| row.blocked_id).collect(); self.load_users_public(&ids).await } async fn load_users_public(&self, ids: &[Uuid]) -> Result, AuthError> { if ids.is_empty() { return Ok(Vec::new()); } let rows = user::Entity::find() .filter(user::Column::Uid.is_in(ids.iter().copied())) .all(self.db().read()) .await?; Ok(rows .into_iter() .map(|user| UserPublic { uid: user.uid, username: user.username, display_name: user.display_name, avatar_url: user.avatar_url, }) .collect()) } }