71 lines
2.1 KiB
Rust
71 lines
2.1 KiB
Rust
use db::sqlx;
|
|
use model::users::UserModel;
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
use crate::{AppService, error::AppError};
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize, utoipa::ToSchema)]
|
|
pub struct UserSummaryResponse {
|
|
pub username: String,
|
|
pub display_name: String,
|
|
pub avatar_url: String,
|
|
pub website_url: String,
|
|
#[schema(value_type = String)]
|
|
pub created_at: chrono::DateTime<chrono::Utc>,
|
|
}
|
|
|
|
impl AppService {
|
|
pub async fn users_summary_by_username(
|
|
&self,
|
|
username: &str,
|
|
) -> Result<UserSummaryResponse, AppError> {
|
|
let user = self.users_find_active_user_by_username(username).await?;
|
|
Ok(user.into())
|
|
}
|
|
|
|
/// Get a user's avatar URL by username.
|
|
pub async fn users_get_avatar_url(
|
|
&self,
|
|
username: &str,
|
|
) -> Result<String, AppError> {
|
|
let user = self.users_find_active_user_by_username(username).await?;
|
|
if user.avatar_url.is_empty() {
|
|
return Err(AppError::NotFound("avatar not found".to_string()));
|
|
}
|
|
Ok(user.avatar_url)
|
|
}
|
|
|
|
pub async fn users_find_active_user_by_username(
|
|
&self,
|
|
username: &str,
|
|
) -> Result<UserModel, AppError> {
|
|
let user = sqlx::query_as::<_, UserModel>(
|
|
"SELECT id, username, display_name, avatar_url, website_url, allow_use, can_search, \
|
|
last_sign_in_at, created_at, updated_at \
|
|
FROM \"user\" WHERE username = $1",
|
|
)
|
|
.bind(username)
|
|
.fetch_optional(self.db.reader())
|
|
.await
|
|
.map_err(|e| AppError::DatabaseError(e.to_string()))?
|
|
.ok_or(AppError::UserNotFound)?;
|
|
|
|
if !user.allow_use {
|
|
return Err(AppError::UserNotFound);
|
|
}
|
|
Ok(user)
|
|
}
|
|
}
|
|
|
|
impl From<UserModel> for UserSummaryResponse {
|
|
fn from(value: UserModel) -> Self {
|
|
Self {
|
|
username: value.username,
|
|
display_name: value.display_name,
|
|
avatar_url: value.avatar_url,
|
|
website_url: value.website_url,
|
|
created_at: value.created_at,
|
|
}
|
|
}
|
|
}
|