use crate::api::error::ApiError; use crate::api::middleware::AuthedUser; use crate::api::pagination::{Page, PageQuery}; use crate::api::state::AppState; use crate::database::UserRow; use axum::extract::{Extension, Query}; use axum::Json; use hbb_common::ResultType; use serde::Serialize; use std::sync::Arc; #[derive(Debug, Serialize)] pub struct UserPayload { pub name: String, pub display_name: String, pub avatar: String, pub email: String, pub note: String, pub status: i64, pub is_admin: bool, } impl From<&UserRow> for UserPayload { fn from(u: &UserRow) -> Self { Self { name: u.username.clone(), display_name: u.display_name.clone(), avatar: u.avatar.clone(), email: u.email.clone(), note: u.note.clone(), status: u.status, is_admin: u.is_admin, } } } pub async fn hash_password(plain: String) -> ResultType { Ok( hbb_common::tokio::task::spawn_blocking(move || bcrypt::hash(plain, 10)) .await??, ) } pub async fn verify_password(hash: String, plain: String) -> ResultType { Ok( hbb_common::tokio::task::spawn_blocking(move || bcrypt::verify(plain, &hash)) .await??, ) } /// `GET /api/users` — paginated list of users visible to the caller. Admin /// sees all enabled users; non-admin sees themselves plus members of any /// device-group they share. Flutter decoder at common/hbbs/hbbs.dart:26. pub async fn list( Extension(state): Extension>, user: AuthedUser, Query(q): Query, ) -> Result>, ApiError> { let (total, rows) = state .db .users_list_accessible(user.user_id, user.is_admin, q.offset(), q.limit()) .await .map_err(|e| ApiError::Internal(e.to_string()))?; Ok(Json(Page { total, data: rows.iter().map(UserPayload::from).collect(), })) }