163952e
use std::collections::HashMap;
use proto::auth::common::v1::UserPublic;
use crate::AppState;
use crate::error::ExportError;
/// Bulk identity lookup. KenApi keeps no local copy of usernames, display
/// names or avatars: every caller goes through KenOAuth.
pub async fn load_public_users(
state: &AppState,
uids: &[i64],
) -> Result<HashMap<i64, UserPublic>, ExportError> {
if uids.is_empty() {
return Ok(HashMap::new());
}
let mut ids: Vec<i64> = uids.to_vec();
ids.sort_unstable();
ids.dedup();
let client = state
.kenauth
.as_ref()
.ok_or_else(|| ExportError::InvalidConfig("kenoauth is not configured".to_string()))?;
let users = client
.batch_get_user_public(ids)
.await
.map_err(|error| ExportError::Connection(error.to_string()))?;
Ok(users.into_iter().map(|user| (user.user_id, user)).collect())
}
pub async fn get_public_user(
state: &AppState,
uid: i64,
) -> Result<Option<UserPublic>, ExportError> {
let client = state
.kenauth
.as_ref()
.ok_or_else(|| ExportError::InvalidConfig("kenoauth is not configured".to_string()))?;
match client.get_user_public(uid).await {
Ok(user) => Ok(Some(user)),
Err(crate::KenAuthError::NotFound) => Ok(None),
Err(error) => Err(ExportError::Connection(error.to_string())),
}
}
pub async fn find_by_email(
state: &AppState,
email: &str,
) -> Result<Option<UserPublic>, ExportError> {
let client = state
.kenauth
.as_ref()
.ok_or_else(|| ExportError::InvalidConfig("kenoauth is not configured".to_string()))?;
match client
.get_user_public_by_ref(proto::auth::common::v1::user_ref::Key::Email(
email.to_string(),
))
.await
{
Ok(user) => Ok(Some(user)),
Err(crate::KenAuthError::NotFound) => Ok(None),
Err(error) => Err(ExportError::Connection(error.to_string())),
}
}
pub async fn find_by_username(
state: &AppState,
username: &str,
) -> Result<Option<UserPublic>, ExportError> {
let client = state
.kenauth
.as_ref()
.ok_or_else(|| ExportError::InvalidConfig("kenoauth is not configured".to_string()))?;
match client
.get_user_public_by_ref(proto::auth::common::v1::user_ref::Key::Username(
username.to_string(),
))
.await
{
Ok(user) => Ok(Some(user)),
Err(crate::KenAuthError::NotFound) => Ok(None),
Err(error) => Err(ExportError::Connection(error.to_string())),
}
}
/// Create the local settings/anchor row on demand. It contains no identity
/// projection; it exists so local preferences and foreign keys have a stable
/// row even when the user never went through KenApi's login callback.
pub async fn ensure_local_user(state: &AppState, uid: i64) -> Result<(), ExportError> {
use models::users::user::{self, ProfileVisibility};
use sea_orm::{ActiveModelTrait, EntityTrait, Set};
let db = state.database.write();
if user::Entity::find_by_id(uid).one(db).await?.is_some() {
return Ok(());
}
user::ActiveModel {
uid: Set(uid),
is_restricted: Set(false),
visibility: Set(ProfileVisibility::Public),
last_login_at: Set(None),
last_login_ip_hash: Set(None),
local_avatar_url: Set(String::new()),
timezone: Set(None),
locale: Set(None),
language: Set(None),
version: Set(1),
updated_at: Set(time::OffsetDateTime::now_utc()),
}
.insert(db)
.await?;
Ok(())
}