This commit is contained in:
tsuki 2025-07-29 22:17:40 +08:00
parent d194c0941a
commit 378094744b
3 changed files with 63 additions and 15 deletions

View File

@ -38,12 +38,18 @@ impl QueryRoot {
ctx: &Context<'_>, ctx: &Context<'_>,
offset: Option<i64>, offset: Option<i64>,
limit: Option<i64>, limit: Option<i64>,
sort_by: Option<String>,
sort_order: Option<String>,
) -> Result<Vec<User>> { ) -> Result<Vec<User>> {
let user_service = ctx.data::<UserService>()?; let user_service = ctx.data::<UserService>()?;
info!("users im here"); info!("users im here");
let offset = offset.unwrap_or(0); let offset = offset.unwrap_or(0);
let limit = limit.unwrap_or(20); let limit = limit.unwrap_or(20);
user_service.get_all_users(offset, limit).await let sort_by = sort_by.unwrap_or("created_at".to_string());
let sort_order = sort_order.unwrap_or("desc".to_string());
user_service
.get_all_users(offset, limit, sort_by, sort_order)
.await
} }
#[graphql(guard = "RequireRole(Role::User)")] #[graphql(guard = "RequireRole(Role::User)")]
@ -64,8 +70,21 @@ impl QueryRoot {
} }
#[graphql(guard = "RequireRole(Role::Admin)")] #[graphql(guard = "RequireRole(Role::Admin)")]
async fn users_info(&self, ctx: &Context<'_>) -> Result<UserInfoRespnose> { async fn users_info(
&self,
ctx: &Context<'_>,
offset: Option<i64>,
limit: Option<i64>,
) -> Result<UserInfoRespnose> {
let user_service = ctx.data::<UserService>()?; let user_service = ctx.data::<UserService>()?;
user_service.users_info().await let offset = offset.unwrap_or(0);
let limit = limit.unwrap_or(20);
let sort_by = "created_at";
let sort_order = "desc";
user_service
.users_info(offset, limit, sort_by, sort_order)
.await
} }
} }

View File

@ -67,4 +67,6 @@ pub struct UserInfoRespnose {
pub total_inactive_users: i64, pub total_inactive_users: i64,
pub total_admin_users: i64, pub total_admin_users: i64,
pub total_user_users: i64, pub total_user_users: i64,
pub users: Vec<crate::models::user::User>,
} }

View File

@ -177,16 +177,31 @@ impl UserService {
Ok(user) Ok(user)
} }
pub async fn get_all_users(&self, offset: i64, limit: i64) -> Result<Vec<User>> { pub async fn get_all_users(
let users = sqlx::query_as!( &self,
User, offset: i64,
r#"SELECT id, username, email, password_hash, role as "role: Role", invite_code_id, is_activate, created_at, updated_at FROM users LIMIT $1 OFFSET $2"#, limit: i64,
limit, sort_by: String,
offset sort_order: String,
) ) -> Result<Vec<User>> {
.fetch_all(&self.pool) // 验证排序字段防止SQL注入
.await let sort_by = match sort_by.as_str() {
.map_err(|e| Error::new(format!("Database error: {}", e)))?; "username" | "email" | "created_at" | "updated_at" | "role" | "is_activate" => sort_by,
_ => "created_at".to_string(), // 默认排序字段
};
let sort_order = if sort_order == "asc" { "ASC" } else { "DESC" };
// 动态构建SQL查询因为列名和排序方向不能参数化
let query = format!(
r#"SELECT id, username, email, password_hash, role as "role: Role", invite_code_id, is_activate, created_at, updated_at FROM users ORDER BY {} {} LIMIT $1 OFFSET $2"#,
sort_by, sort_order
);
let users = sqlx::query_as!(User, &query, limit, offset)
.fetch_all(&self.pool)
.await
.map_err(|e| Error::new(format!("Database error: {}", e)))?;
info!("users: {:?}", users); info!("users: {:?}", users);
@ -281,7 +296,16 @@ impl UserService {
.is_ok()) .is_ok())
} }
pub async fn users_info(&self) -> Result<UserInfoRespnose> { pub async fn users_info(
&self,
offset: i64,
limit: i64,
sort_by: impl Into<String>,
sort_order: impl Into<String>,
) -> Result<UserInfoRespnose> {
let sort_by = sort_by.into();
let sort_order = sort_order.into();
let total_users = sqlx::query_scalar!(r#"SELECT COUNT(*) FROM users"#) let total_users = sqlx::query_scalar!(r#"SELECT COUNT(*) FROM users"#)
.fetch_one(&self.pool) .fetch_one(&self.pool)
.await .await
@ -300,7 +324,7 @@ impl UserService {
.map_err(|e| Error::new(format!("Database error: {}", e)))?; .map_err(|e| Error::new(format!("Database error: {}", e)))?;
let total_admin_users = let total_admin_users =
sqlx::query_scalar!(r#"SELECT COUNT(*) FROM users WHERE role = 'admin'"#) sqlx::query_scalar!(r#"SELECT COUNT(*) FROM users WHERE role = 'Admin'"#)
.fetch_one(&self.pool) .fetch_one(&self.pool)
.await .await
.map_err(|e| Error::new(format!("Database error: {}", e)))?; .map_err(|e| Error::new(format!("Database error: {}", e)))?;
@ -311,12 +335,15 @@ impl UserService {
.await .await
.map_err(|e| Error::new(format!("Database error: {}", e)))?; .map_err(|e| Error::new(format!("Database error: {}", e)))?;
let users = self.get_all_users(offset, limit, sort_by, sort_order).await;
Ok(UserInfoRespnose { Ok(UserInfoRespnose {
total_users: total_users.unwrap_or(0), total_users: total_users.unwrap_or(0),
total_active_users: total_active_users.unwrap_or(0), total_active_users: total_active_users.unwrap_or(0),
total_inactive_users: total_inactive_users.unwrap_or(0), total_inactive_users: total_inactive_users.unwrap_or(0),
total_admin_users: total_admin_users.unwrap_or(0), total_admin_users: total_admin_users.unwrap_or(0),
total_user_users: total_user_users.unwrap_or(0), total_user_users: total_user_users.unwrap_or(0),
users: users.unwrap_or_default(),
}) })
} }
} }