feat: 完成Rust User API完整开发
Some checks failed
Deploy to Production / Run Tests (push) Failing after 16m35s
Deploy to Production / Security Scan (push) Has been skipped
Deploy to Production / Build Docker Image (push) Has been skipped
Deploy to Production / Deploy to Staging (push) Has been skipped
Deploy to Production / Deploy to Production (push) Has been skipped
Deploy to Production / Notify Results (push) Successful in 31s
Some checks failed
Deploy to Production / Run Tests (push) Failing after 16m35s
Deploy to Production / Security Scan (push) Has been skipped
Deploy to Production / Build Docker Image (push) Has been skipped
Deploy to Production / Deploy to Staging (push) Has been skipped
Deploy to Production / Deploy to Production (push) Has been skipped
Deploy to Production / Notify Results (push) Successful in 31s
✨ 新功能: - SQLite数据库集成和持久化存储 - 数据库迁移系统和版本管理 - API分页功能和高效查询 - 用户搜索和过滤机制 - 完整的RBAC角色权限系统 - 结构化日志记录和系统监控 - API限流和多层安全防护 - Docker容器化和生产部署配置 🔒 安全特性: - JWT认证和授权 - 限流和防暴力破解 - 安全头和CORS配置 - 输入验证和XSS防护 - 审计日志和安全监控 📊 监控和运维: - Prometheus指标收集 - 健康检查和系统监控 - 自动化备份和恢复 - 完整的运维文档和脚本 - CI/CD流水线配置 🚀 部署支持: - 多环境Docker配置 - 生产环境部署指南 - 性能优化和安全加固 - 故障排除和应急响应 - 自动化运维脚本 📚 文档完善: - API使用文档 - 部署检查清单 - 运维操作手册 - 性能和安全指南 - 故障排除指南
This commit is contained in:
@@ -7,6 +7,7 @@ use chrono::{DateTime, Utc};
|
||||
use crate::models::user::User;
|
||||
use crate::models::pagination::PaginationParams;
|
||||
use crate::models::search::UserSearchParams;
|
||||
use crate::models::role::UserRole;
|
||||
use crate::utils::errors::ApiError;
|
||||
use crate::storage::{UserStore, MigrationManager};
|
||||
|
||||
@@ -50,14 +51,15 @@ impl DatabaseUserStore {
|
||||
async fn create_user_impl(&self, user: User) -> Result<User, ApiError> {
|
||||
let result = sqlx::query(
|
||||
r#"
|
||||
INSERT INTO users (id, username, email, password_hash, created_at, updated_at)
|
||||
VALUES (?, ?, ?, ?, ?, ?)
|
||||
INSERT INTO users (id, username, email, password_hash, role, created_at, updated_at)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?)
|
||||
"#,
|
||||
)
|
||||
.bind(user.id.to_string())
|
||||
.bind(&user.username)
|
||||
.bind(&user.email)
|
||||
.bind(&user.password_hash)
|
||||
.bind(user.role.as_str())
|
||||
.bind(user.created_at.to_rfc3339())
|
||||
.bind(user.updated_at.to_rfc3339())
|
||||
.execute(&self.pool)
|
||||
@@ -75,7 +77,7 @@ impl DatabaseUserStore {
|
||||
/// 根据 ID 获取用户
|
||||
async fn get_user_impl(&self, id: &Uuid) -> Result<Option<User>, ApiError> {
|
||||
let result = sqlx::query(
|
||||
"SELECT id, username, email, password_hash, created_at, updated_at FROM users WHERE id = ?"
|
||||
"SELECT id, username, email, password_hash, role, created_at, updated_at FROM users WHERE id = ?"
|
||||
)
|
||||
.bind(id.to_string())
|
||||
.fetch_optional(&self.pool)
|
||||
@@ -83,12 +85,16 @@ impl DatabaseUserStore {
|
||||
|
||||
match result {
|
||||
Ok(Some(row)) => {
|
||||
let role_str: String = row.get("role");
|
||||
let role = UserRole::from_str(&role_str).unwrap_or_default();
|
||||
|
||||
let user = User {
|
||||
id: Uuid::parse_str(&row.get::<String, _>("id"))
|
||||
.map_err(|e| ApiError::InternalError(format!("UUID 解析错误: {}", e)))?,
|
||||
username: row.get("username"),
|
||||
email: row.get("email"),
|
||||
password_hash: row.get("password_hash"),
|
||||
role,
|
||||
created_at: DateTime::parse_from_rfc3339(&row.get::<String, _>("created_at"))
|
||||
.map_err(|e| ApiError::InternalError(format!("时间解析错误: {}", e)))?
|
||||
.with_timezone(&Utc),
|
||||
@@ -106,7 +112,7 @@ impl DatabaseUserStore {
|
||||
/// 根据用户名获取用户
|
||||
async fn get_user_by_username_impl(&self, username: &str) -> Result<Option<User>, ApiError> {
|
||||
let result = sqlx::query(
|
||||
"SELECT id, username, email, password_hash, created_at, updated_at FROM users WHERE username = ?"
|
||||
"SELECT id, username, email, password_hash, role, created_at, updated_at FROM users WHERE username = ?"
|
||||
)
|
||||
.bind(username)
|
||||
.fetch_optional(&self.pool)
|
||||
@@ -114,12 +120,16 @@ impl DatabaseUserStore {
|
||||
|
||||
match result {
|
||||
Ok(Some(row)) => {
|
||||
let role_str: String = row.get("role");
|
||||
let role = UserRole::from_str(&role_str).unwrap_or_default();
|
||||
|
||||
let user = User {
|
||||
id: Uuid::parse_str(&row.get::<String, _>("id"))
|
||||
.map_err(|e| ApiError::InternalError(format!("UUID 解析错误: {}", e)))?,
|
||||
username: row.get("username"),
|
||||
email: row.get("email"),
|
||||
password_hash: row.get("password_hash"),
|
||||
role,
|
||||
created_at: DateTime::parse_from_rfc3339(&row.get::<String, _>("created_at"))
|
||||
.map_err(|e| ApiError::InternalError(format!("时间解析错误: {}", e)))?
|
||||
.with_timezone(&Utc),
|
||||
@@ -137,7 +147,7 @@ impl DatabaseUserStore {
|
||||
/// 获取所有用户
|
||||
async fn list_users_impl(&self) -> Result<Vec<User>, ApiError> {
|
||||
let result = sqlx::query(
|
||||
"SELECT id, username, email, password_hash, created_at, updated_at FROM users ORDER BY created_at DESC"
|
||||
"SELECT id, username, email, password_hash, role, created_at, updated_at FROM users ORDER BY created_at DESC"
|
||||
)
|
||||
.fetch_all(&self.pool)
|
||||
.await;
|
||||
@@ -146,12 +156,16 @@ impl DatabaseUserStore {
|
||||
Ok(rows) => {
|
||||
let mut users = Vec::new();
|
||||
for row in rows {
|
||||
let role_str: String = row.get("role");
|
||||
let role = UserRole::from_str(&role_str).unwrap_or_default();
|
||||
|
||||
let user = User {
|
||||
id: Uuid::parse_str(&row.get::<String, _>("id"))
|
||||
.map_err(|e| ApiError::InternalError(format!("UUID 解析错误: {}", e)))?,
|
||||
username: row.get("username"),
|
||||
email: row.get("email"),
|
||||
password_hash: row.get("password_hash"),
|
||||
role,
|
||||
created_at: DateTime::parse_from_rfc3339(&row.get::<String, _>("created_at"))
|
||||
.map_err(|e| ApiError::InternalError(format!("时间解析错误: {}", e)))?
|
||||
.with_timezone(&Utc),
|
||||
@@ -181,7 +195,7 @@ impl DatabaseUserStore {
|
||||
|
||||
// 然后获取分页数据
|
||||
let result = sqlx::query(
|
||||
"SELECT id, username, email, password_hash, created_at, updated_at
|
||||
"SELECT id, username, email, password_hash, role, created_at, updated_at
|
||||
FROM users
|
||||
ORDER BY created_at DESC
|
||||
LIMIT ? OFFSET ?"
|
||||
@@ -195,12 +209,16 @@ impl DatabaseUserStore {
|
||||
Ok(rows) => {
|
||||
let mut users = Vec::new();
|
||||
for row in rows {
|
||||
let role_str: String = row.get("role");
|
||||
let role = UserRole::from_str(&role_str).unwrap_or_default();
|
||||
|
||||
let user = User {
|
||||
id: Uuid::parse_str(&row.get::<String, _>("id"))
|
||||
.map_err(|e| ApiError::InternalError(format!("UUID 解析错误: {}", e)))?,
|
||||
username: row.get("username"),
|
||||
email: row.get("email"),
|
||||
password_hash: row.get("password_hash"),
|
||||
role,
|
||||
created_at: DateTime::parse_from_rfc3339(&row.get::<String, _>("created_at"))
|
||||
.map_err(|e| ApiError::InternalError(format!("时间解析错误: {}", e)))?
|
||||
.with_timezone(&Utc),
|
||||
@@ -292,7 +310,7 @@ impl DatabaseUserStore {
|
||||
|
||||
// 然后获取分页数据
|
||||
let data_query = format!(
|
||||
"SELECT id, username, email, password_hash, created_at, updated_at FROM users {} {} LIMIT ? OFFSET ?",
|
||||
"SELECT id, username, email, password_hash, role, created_at, updated_at FROM users {} {} LIMIT ? OFFSET ?",
|
||||
where_clause, order_clause
|
||||
);
|
||||
|
||||
@@ -314,12 +332,16 @@ impl DatabaseUserStore {
|
||||
Ok(rows) => {
|
||||
let mut users = Vec::new();
|
||||
for row in rows {
|
||||
let role_str: String = row.get("role");
|
||||
let role = UserRole::from_str(&role_str).unwrap_or_default();
|
||||
|
||||
let user = User {
|
||||
id: Uuid::parse_str(&row.get::<String, _>("id"))
|
||||
.map_err(|e| ApiError::InternalError(format!("UUID 解析错误: {}", e)))?,
|
||||
username: row.get("username"),
|
||||
email: row.get("email"),
|
||||
password_hash: row.get("password_hash"),
|
||||
role,
|
||||
created_at: DateTime::parse_from_rfc3339(&row.get::<String, _>("created_at"))
|
||||
.map_err(|e| ApiError::InternalError(format!("时间解析错误: {}", e)))?
|
||||
.with_timezone(&Utc),
|
||||
@@ -339,13 +361,14 @@ impl DatabaseUserStore {
|
||||
async fn update_user_impl(&self, id: &Uuid, updated_user: User) -> Result<Option<User>, ApiError> {
|
||||
let result = sqlx::query(
|
||||
r#"
|
||||
UPDATE users
|
||||
SET username = ?, email = ?, updated_at = ?
|
||||
UPDATE users
|
||||
SET username = ?, email = ?, role = ?, updated_at = ?
|
||||
WHERE id = ?
|
||||
"#,
|
||||
)
|
||||
.bind(&updated_user.username)
|
||||
.bind(&updated_user.email)
|
||||
.bind(updated_user.role.as_str())
|
||||
.bind(updated_user.updated_at.to_rfc3339())
|
||||
.bind(id.to_string())
|
||||
.execute(&self.pool)
|
||||
|
Reference in New Issue
Block a user