Skip to content
Clone
main
136 lines 4.6 KB Rust
use std::collections::HashMap;
use crate::protos::auth::common::v1 as auth_public;
use models::users::user::{self, ProfileVisibility};
use sea_orm::{ColumnTrait, EntityTrait, QueryFilter};
use crate::AuthService;
use crate::errors::AuthBusinessError;
use crate::share::account::types::UserPublic;
const MAX_BATCH_USERS: usize = 100;
impl AuthService {
fn filter_public_user(
&self,
caller: i64,
local: Option<&user::Model>,
public: &auth_public::UserPublic,
allow_use: bool,
) -> Result<UserPublic, AuthBusinessError> {
if !allow_use || public.system {
return Err(AuthBusinessError::NotFound);
}
let visibility = local
.map(|row| row.visibility)
.unwrap_or(ProfileVisibility::Public);
if visibility == ProfileVisibility::Private && caller != public.user_id {
return Err(AuthBusinessError::NotFound);
}
let display_name = if public.displayname.trim().is_empty() {
public.username.clone()
} else {
public.displayname.clone()
};
let avatar_raw = local
.map(|row| row.local_avatar_url.as_str())
.filter(|value| !value.is_empty())
.unwrap_or(public.avatar_url.as_str());
Ok(UserPublic {
user_id: public.user_id,
username: public.username.clone(),
display_name,
avatar_url: api::urls::resolve_user_avatar_url(public.user_id, avatar_raw),
})
}
pub async fn public_user(
&self,
caller: i64,
uid: i64,
) -> Result<UserPublic, AuthBusinessError> {
let client = &self.accounts;
let public = client.get_user_public(uid).await.map_err(map_kenauth)?;
let authority = client.get_authority_user(uid).await.map_err(map_kenauth)?;
let local = user::Entity::find_by_id(uid).one(self.db().read()).await?;
self.filter_public_user(caller, local.as_ref(), &public, authority.allow_use)
}
pub async fn public_users(
&self,
caller: i64,
ids: Vec<i64>,
) -> Result<Vec<UserPublic>, AuthBusinessError> {
if ids.len() > MAX_BATCH_USERS {
return Err(AuthBusinessError::BadRequest(format!(
"ids must contain at most {MAX_BATCH_USERS} entries"
)));
}
if ids.is_empty() {
return Ok(Vec::new());
}
let mut unique: Vec<i64> = ids;
unique.sort_unstable();
unique.dedup();
let client = &self.accounts;
let publics = client
.batch_get_user_public(unique.clone())
.await
.map_err(map_kenauth)?;
let authorities = client
.batch_get_authority_users(unique.clone())
.await
.map_err(map_kenauth)?;
let locals: HashMap<i64, user::Model> = user::Entity::find()
.filter(user::Column::Uid.is_in(unique))
.all(self.db().read())
.await?
.into_iter()
.map(|row| (row.uid, row))
.collect();
let allow: HashMap<i64, bool> = authorities
.into_iter()
.map(|row| (row.id, row.allow_use))
.collect();
let mut out = Vec::with_capacity(publics.len());
for public in publics {
let local = locals.get(&public.user_id);
let allow_use = allow.get(&public.user_id).copied().unwrap_or(false);
if let Ok(user) = self.filter_public_user(caller, local, &public, allow_use) {
out.push(user);
}
}
Ok(out)
}
pub async fn public_user_by_name(
&self,
caller: i64,
username: &str,
) -> Result<UserPublic, AuthBusinessError> {
let name = username.trim();
if name.is_empty() {
return Err(AuthBusinessError::NotFound);
}
let client = &self.accounts;
let public = client
.get_user_public_by_ref(auth_public::user_ref::Key::Username(name.to_string()))
.await
.map_err(map_kenauth)?;
self.public_user(caller, public.user_id).await
}
}
fn map_kenauth(error: crate::errors::KenAuthError) -> AuthBusinessError {
use crate::errors::KenAuthError;
match error {
KenAuthError::NotFound => AuthBusinessError::NotFound,
KenAuthError::Unauthenticated => AuthBusinessError::Unauthorized,
KenAuthError::Rejected(message) => AuthBusinessError::BadRequest(message),
KenAuthError::Unavailable(message)
| KenAuthError::Config(message)
| KenAuthError::Internal(message) => AuthBusinessError::Internal(message),
}
}