添加管理员API端点
- .env 添加 FREE_USER_DATA_LIMIT 配置
- 新增 GET /api/admin/users/{id} 管理员获取用户信息
- 新增 PUT /api/admin/users/{id}/payment 更新用户付费状态
- post_weather_data 集成 JWT 认证,使用 claims.user_id
- 管理员接口通过数据库查询验证 is_admin
This commit is contained in:
3
.env
3
.env
@@ -6,4 +6,5 @@ JWT_SECRET="your_super_secret_key"
|
||||
SSL_KEY_PATH=/etc/ssl/private/private.key
|
||||
SSL_CERT_PATH=/etc/ssl/certs/full_chain.pem
|
||||
RUST_LOG=info
|
||||
APP_VERSION="0.2.0"
|
||||
APP_VERSION="0.2.0"
|
||||
FREE_USER_DATA_LIMIT=20
|
||||
133
src/main.rs
133
src/main.rs
@@ -1,5 +1,5 @@
|
||||
use actix_web::middleware::from_fn;
|
||||
use actix_web::{App, HttpResponse, HttpServer, Responder, delete, get, post, web};
|
||||
use actix_web::{App, HttpResponse, HttpServer, Responder, delete, get, post, put, web};
|
||||
use include_dir::{Dir, include_dir};
|
||||
use log::{debug, error, info, warn};
|
||||
use openssl::ssl::{SslAcceptor, SslAcceptorBuilder, SslFiletype, SslMethod};
|
||||
@@ -14,7 +14,7 @@ use auth::{generate_token, jwt_middleware};
|
||||
use db::{create_pool, insert_weather_data};
|
||||
use models::{ErrorResponse, WeChatApiResponse, WeChatLoginRequest, WeatherData};
|
||||
|
||||
use crate::models::{Claims, TokenResponse};
|
||||
use crate::models::{Claims, TokenResponse, UpdatePaymentRequest};
|
||||
|
||||
// 编译时嵌入整个 static 目录
|
||||
static STATIC_DIR: Dir = include_dir!("$CARGO_MANIFEST_DIR/static");
|
||||
@@ -214,11 +214,14 @@ async fn login(
|
||||
async fn post_weather_data(
|
||||
data: web::Json<WeatherData>,
|
||||
pool: web::Data<PgPool>,
|
||||
claims: web::ReqData<Claims>,
|
||||
) -> impl Responder {
|
||||
info!("Received weather data, preparing to insert into DB...");
|
||||
|
||||
let user_id = claims.user_id;
|
||||
|
||||
// 调用 db.rs 中的函数来处理数据库逻辑
|
||||
match insert_weather_data(pool.get_ref(), &data).await {
|
||||
match insert_weather_data(pool.get_ref(), &data, user_id).await {
|
||||
Ok(inserted_id) => {
|
||||
info!(
|
||||
"Successfully inserted weather data with id: {}",
|
||||
@@ -233,14 +236,9 @@ async fn post_weather_data(
|
||||
}
|
||||
Err(error_msg) => {
|
||||
error!("Database operation failed: {}", error_msg);
|
||||
// 根据错误信息返回统一格式的错误响应
|
||||
let mut errcode = 500;
|
||||
if error_msg.starts_with("未找到openid") {
|
||||
errcode = 404;
|
||||
}
|
||||
HttpResponse::Ok().json(serde_json::json!({
|
||||
"success": false,
|
||||
"errcode": errcode,
|
||||
"errcode": 500,
|
||||
"errmsg": error_msg
|
||||
}))
|
||||
}
|
||||
@@ -547,6 +545,119 @@ async fn delete_weather(
|
||||
}
|
||||
}
|
||||
|
||||
// 管理员获取用户信息
|
||||
#[get("/api/admin/users/{id}")]
|
||||
async fn admin_get_user(
|
||||
path: web::Path<i32>,
|
||||
pool: web::Data<PgPool>,
|
||||
claims: web::ReqData<Claims>,
|
||||
) -> impl Responder {
|
||||
let target_user_id = path.into_inner();
|
||||
info!("管理员获取用户信息, 目标用户ID: {}", target_user_id);
|
||||
|
||||
// 验证当前用户是否为管理员
|
||||
let current_user = match db::get_user_by_id(pool.get_ref(), claims.user_id).await {
|
||||
Ok(user) => user,
|
||||
Err(e) => {
|
||||
error!("获取当前用户信息失败: {}", e);
|
||||
return HttpResponse::Ok().json(serde_json::json!({
|
||||
"success": false,
|
||||
"errcode": 500,
|
||||
"errmsg": "获取用户信息失败"
|
||||
}));
|
||||
}
|
||||
};
|
||||
|
||||
if !current_user.is_admin {
|
||||
return HttpResponse::Forbidden().json(serde_json::json!({
|
||||
"success": false,
|
||||
"errcode": 403,
|
||||
"errmsg": "无权限执行此操作"
|
||||
}));
|
||||
}
|
||||
|
||||
// 获取目标用户信息
|
||||
match db::get_user_by_id(pool.get_ref(), target_user_id).await {
|
||||
Ok(user) => HttpResponse::Ok().json(serde_json::json!({
|
||||
"success": true,
|
||||
"data": user
|
||||
})),
|
||||
Err(e) => {
|
||||
error!("获取目标用户信息失败: {}", e);
|
||||
let errcode = if e.starts_with("未找到") { 404 } else { 500 };
|
||||
HttpResponse::Ok().json(serde_json::json!({
|
||||
"success": false,
|
||||
"errcode": errcode,
|
||||
"errmsg": e
|
||||
}))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 管理员更新用户付费状态
|
||||
#[put("/api/admin/users/{id}/payment")]
|
||||
async fn admin_update_user_payment(
|
||||
path: web::Path<i32>,
|
||||
pool: web::Data<PgPool>,
|
||||
claims: web::ReqData<Claims>,
|
||||
body: web::Json<UpdatePaymentRequest>,
|
||||
) -> impl Responder {
|
||||
let target_user_id = path.into_inner();
|
||||
info!("管理员更新用户付费状态, 目标用户ID: {}", target_user_id);
|
||||
|
||||
// 验证当前用户是否为管理员
|
||||
let current_user = match db::get_user_by_id(pool.get_ref(), claims.user_id).await {
|
||||
Ok(user) => user,
|
||||
Err(e) => {
|
||||
error!("获取当前用户信息失败: {}", e);
|
||||
return HttpResponse::Ok().json(serde_json::json!({
|
||||
"success": false,
|
||||
"errcode": 500,
|
||||
"errmsg": "获取用户信息失败"
|
||||
}));
|
||||
}
|
||||
};
|
||||
|
||||
if !current_user.is_admin {
|
||||
return HttpResponse::Forbidden().json(serde_json::json!({
|
||||
"success": false,
|
||||
"errcode": 403,
|
||||
"errmsg": "无权限执行此操作"
|
||||
}));
|
||||
}
|
||||
|
||||
// 解析 paid_expires_at
|
||||
let paid_expires_at = match &body.paid_expires_at {
|
||||
Some(date_str) => match chrono::DateTime::parse_from_rfc3339(date_str) {
|
||||
Ok(dt) => Some(dt.with_timezone(&chrono::Utc)),
|
||||
Err(e) => {
|
||||
return HttpResponse::BadRequest().json(serde_json::json!({
|
||||
"success": false,
|
||||
"errcode": 400,
|
||||
"errmsg": format!("日期格式错误: {}", e)
|
||||
}));
|
||||
}
|
||||
},
|
||||
None => None,
|
||||
};
|
||||
|
||||
// 更新用户付费状态
|
||||
match db::update_user_payment_status(pool.get_ref(), target_user_id, body.is_paid, paid_expires_at).await {
|
||||
Ok(_) => HttpResponse::Ok().json(serde_json::json!({
|
||||
"success": true,
|
||||
"message": "用户付费状态已更新"
|
||||
})),
|
||||
Err(e) => {
|
||||
error!("更新用户付费状态失败: {}", e);
|
||||
HttpResponse::Ok().json(serde_json::json!({
|
||||
"success": false,
|
||||
"errcode": 500,
|
||||
"errmsg": e
|
||||
}))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 在 main.rs 中添加以下函数,用于处理静态文件请求
|
||||
async fn serve_static_files(path: web::Path<String>) -> impl Responder {
|
||||
// 获取请求的文件路径(例如 "css/style.css")
|
||||
@@ -615,7 +726,9 @@ fn create_server_config(
|
||||
.service(post_weather_data)
|
||||
.service(get_weather_brief) // 新增
|
||||
.service(generate_temp_token_handler)
|
||||
.service(delete_weather),
|
||||
.service(delete_weather)
|
||||
.service(admin_get_user)
|
||||
.service(admin_update_user_payment),
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user