diff --git a/src/graphql/query.rs b/src/graphql/query.rs index 9392f3f..f42a65f 100644 --- a/src/graphql/query.rs +++ b/src/graphql/query.rs @@ -38,12 +38,18 @@ impl QueryRoot { ctx: &Context<'_>, offset: Option, limit: Option, + sort_by: Option, + sort_order: Option, ) -> Result> { let user_service = ctx.data::()?; info!("users im here"); let offset = offset.unwrap_or(0); 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)")] @@ -64,8 +70,21 @@ impl QueryRoot { } #[graphql(guard = "RequireRole(Role::Admin)")] - async fn users_info(&self, ctx: &Context<'_>) -> Result { + async fn users_info( + &self, + ctx: &Context<'_>, + offset: Option, + limit: Option, + ) -> Result { let user_service = ctx.data::()?; - 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 } } diff --git a/src/graphql/types.rs b/src/graphql/types.rs index 5202946..2e1a355 100644 --- a/src/graphql/types.rs +++ b/src/graphql/types.rs @@ -67,4 +67,6 @@ pub struct UserInfoRespnose { pub total_inactive_users: i64, pub total_admin_users: i64, pub total_user_users: i64, + + pub users: Vec, } diff --git a/src/services/user_service.rs b/src/services/user_service.rs index ca90838..afe1649 100644 --- a/src/services/user_service.rs +++ b/src/services/user_service.rs @@ -177,16 +177,31 @@ impl UserService { Ok(user) } - pub async fn get_all_users(&self, offset: i64, limit: i64) -> Result> { - let users = sqlx::query_as!( - User, - 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, - offset - ) - .fetch_all(&self.pool) - .await - .map_err(|e| Error::new(format!("Database error: {}", e)))?; + pub async fn get_all_users( + &self, + offset: i64, + limit: i64, + sort_by: String, + sort_order: String, + ) -> Result> { + // 验证排序字段,防止SQL注入 + let sort_by = match sort_by.as_str() { + "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); @@ -281,7 +296,16 @@ impl UserService { .is_ok()) } - pub async fn users_info(&self) -> Result { + pub async fn users_info( + &self, + offset: i64, + limit: i64, + sort_by: impl Into, + sort_order: impl Into, + ) -> Result { + let sort_by = sort_by.into(); + let sort_order = sort_order.into(); + let total_users = sqlx::query_scalar!(r#"SELECT COUNT(*) FROM users"#) .fetch_one(&self.pool) .await @@ -300,7 +324,7 @@ impl UserService { .map_err(|e| Error::new(format!("Database error: {}", e)))?; 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) .await .map_err(|e| Error::new(format!("Database error: {}", e)))?; @@ -311,12 +335,15 @@ impl UserService { .await .map_err(|e| Error::new(format!("Database error: {}", e)))?; + let users = self.get_all_users(offset, limit, sort_by, sort_order).await; + Ok(UserInfoRespnose { total_users: total_users.unwrap_or(0), total_active_users: total_active_users.unwrap_or(0), total_inactive_users: total_inactive_users.unwrap_or(0), total_admin_users: total_admin_users.unwrap_or(0), total_user_users: total_user_users.unwrap_or(0), + users: users.unwrap_or_default(), }) } }