diff --git a/Cargo.lock b/Cargo.lock index a46b3ae..69e882b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -477,6 +477,7 @@ name = "domain" version = "0.1.0" dependencies = [ "chrono", + "i18n", "serde", "serde_json", "sqlx", diff --git a/api/src/controller/account.rs b/api/src/controller/account.rs index 3e39c67..fb59bd4 100644 --- a/api/src/controller/account.rs +++ b/api/src/controller/account.rs @@ -3,19 +3,17 @@ use domain::{dto::account::{AuthenticateGooleAccountReq, AuthenticateWithPasswor use library::{context::Context, res::{response::{ ResData, ResResult}, validator}}; pub async fn authenticate_google( - Extension(context): Extension, Json(req): Json ) -> ResResult> { - validator::validate_params(&req, "")?; - service::account::authenticate_google(context, req).await + validator::validate_params(&req, &req.lang_tag.to_owned().unwrap())?; + service::account::authenticate_google(req).await } pub async fn authenticate_with_password( - Extension(context): Extension, Json(req): Json ) -> ResResult> { - validator::validate_params(&req, "")?; - service::sys_account::authenticate_with_password(context, req).await + validator::validate_params(&req, &req.lang_tag.to_owned().unwrap())?; + service::sys_account::authenticate_with_password(req).await } pub async fn refresh_token( diff --git a/api/src/controller/feedback.rs b/api/src/controller/feedback.rs index 1c61c83..223c003 100644 --- a/api/src/controller/feedback.rs +++ b/api/src/controller/feedback.rs @@ -1,5 +1,6 @@ use axum::extract::Query; -use axum::Json; +use axum::{Extension, Json}; +use library::context::Context; use validator::Validate; use domain::dto::feedback::FeedbackAdd; use domain::dto::pageable::PageParams; @@ -9,11 +10,12 @@ use library::res::response::{ResData, ResResult}; /// 添加反馈信息 pub async fn add_feedback( + Extension(context): Extension, Json(req): Json ) -> ResResult> { req.validate()?; - service::feedback::add_feedback(req).await + service::feedback::add_feedback(context, req).await } /// 获取反馈信息列表 diff --git a/domain/Cargo.toml b/domain/Cargo.toml index 9d9436a..f65082b 100644 --- a/domain/Cargo.toml +++ b/domain/Cargo.toml @@ -14,3 +14,5 @@ chrono = { workspace = true, features = ["serde"]} tracing = { workspace = true } tracing-appender = { workspace = true } tracing-subscriber = { workspace = true, features = ["json"] } + +i18n = { path = "../i18n" } \ No newline at end of file diff --git a/domain/src/dto/account.rs b/domain/src/dto/account.rs index 73d80a6..e60aa59 100644 --- a/domain/src/dto/account.rs +++ b/domain/src/dto/account.rs @@ -3,16 +3,20 @@ use validator::Validate; #[derive(Debug, Validate, Deserialize, Serialize)] pub struct AuthenticateWithPassword { - #[validate(required(message = "用户名不能为空"), length(min = 1, message = "用户名不能为空"))] + #[validate(required(message = "VALIDATE_ACCOUNT_NAME_REQUIRED"), length(min = 1, message = "VALIDATE_ACCOUNT_NAME_REQUIRED"))] pub username: Option, - #[validate(required(message = "密码不能为空"), length(min = 1, message = "密码不能为空"))] + #[validate(required(message = "VALIDATE_ACCOUNT_PASSWORD_REQUIRED"), length(min = 1, message = "VALIDATE_ACCOUNT_PASSWORD_REQUIRED"))] pub password: Option, + #[validate(required(message = "VALIDATE_ACCOUNT_LANG_TAG_REQUIRED"), length(min = 1, message = "VALIDATE_ACCOUNT_LANG_TAG_REQUIRED"))] + pub lang_tag: Option, } #[derive(Debug, Validate, Deserialize, Serialize)] pub struct AuthenticateGooleAccountReq { - #[validate(required(message = "用户ID Token不能为空"), length(min = 1, message = "用户ID Token不能为空"))] + #[validate(required(message = "VALIDATE_ACCOUNT_ID_TOKEN_REQUIRED"), length(min = 1, message = "VALIDATE_ACCOUNT_ID_TOKEN_REQUIRED"))] pub id_token: Option, + #[validate(required(message = "VALIDATE_ACCOUNT_LANG_TAG_REQUIRED"), length(min = 1, message = "VALIDATE_ACCOUNT_LANG_TAG_REQUIRED"))] + pub lang_tag: Option, } #[derive(Debug, Validate, Deserialize, Serialize)] diff --git a/domain/src/dto/feedback.rs b/domain/src/dto/feedback.rs index c971e20..3c220bb 100644 --- a/domain/src/dto/feedback.rs +++ b/domain/src/dto/feedback.rs @@ -1,10 +1,9 @@ use serde::{Deserialize, Serialize}; use validator::Validate; + #[derive(Debug, Validate, Deserialize, Serialize)] pub struct FeedbackAdd { - #[validate(required(message = "用户ID不能为空"))] - pub user_id: Option, - #[validate(required(message = "反馈内容不能为空"), length(min = 1, message = "反馈内容不能为空"))] + #[validate(required(message = "VALIDATE_FEEDBACK_CONTENT_REQUIRED"), length(min = 1, message = "VALIDATE_FEEDBACK_CONTENT_REQUIRED"))] pub content: Option } \ No newline at end of file diff --git a/domain/src/entities/feedback.rs b/domain/src/entities/feedback.rs index b5500e7..6a42c94 100644 --- a/domain/src/entities/feedback.rs +++ b/domain/src/entities/feedback.rs @@ -7,7 +7,7 @@ use crate::db_result::CountResult; #[derive(Debug, Clone, Deserialize, Default, Serialize)] pub struct Feedback { pub id: i64, - pub user_id: i64, + pub user_id: String, pub content: String, pub created_at: NaiveDateTime, } diff --git a/i18n/src/en_us.rs b/i18n/src/en_us.rs index 5d233f1..dbd5f8c 100644 --- a/i18n/src/en_us.rs +++ b/i18n/src/en_us.rs @@ -3,10 +3,10 @@ use std::collections::HashMap; use lazy_static::lazy_static; use crate::message_ids::{ - ACCOUNT_DISABLED, ACCOUNT_NO_PERMISSION, HELLO, INCORRECT_USERNAME_OR_PASSWORD, INVALID_TOKEN, + ACCOUNT_DISABLED, ACCOUNT_NO_PERMISSION, HELLO, INCORRECT_USERNAME_OR_PASSWORD, INVALID_TOKEN, VALIDATE_ACCOUNT_ID_TOKEN_REQUIRED, VALIDATE_ACCOUNT_LANG_TAG_REQUIRED, VALIDATE_ACCOUNT_NAME_REQUIRED, VALIDATE_ACCOUNT_PASSWORD_REQUIRED, VALIDATE_FEEDBACK_CONTENT_REQUIRED }; -pub const LANGUAGE_ID: &str = "en-US"; +pub const LANGUAGE_ID: &str = "en_US"; lazy_static! { pub static ref MESSAGE: HashMap<&'static str, &'static str> = { @@ -14,11 +14,14 @@ lazy_static! { map.insert(HELLO, "hello {}"); map.insert(ACCOUNT_DISABLED, "account is disabled"); map.insert(ACCOUNT_NO_PERMISSION, "account has no permission"); - map.insert( - INCORRECT_USERNAME_OR_PASSWORD, - "incorrect username or password", - ); + map.insert(INCORRECT_USERNAME_OR_PASSWORD,"incorrect username or password"); map.insert(INVALID_TOKEN, "invalid token"); + + map.insert(VALIDATE_FEEDBACK_CONTENT_REQUIRED, "feedback content is required"); + map.insert(VALIDATE_ACCOUNT_NAME_REQUIRED, "username is required"); + map.insert(VALIDATE_ACCOUNT_PASSWORD_REQUIRED, "password is required"); + map.insert(VALIDATE_ACCOUNT_ID_TOKEN_REQUIRED, "ID Token is required"); + map.insert(VALIDATE_ACCOUNT_LANG_TAG_REQUIRED, "lang tag is required"); map }; } diff --git a/i18n/src/lib.rs b/i18n/src/lib.rs index 1196808..ec71beb 100644 --- a/i18n/src/lib.rs +++ b/i18n/src/lib.rs @@ -19,7 +19,7 @@ fn get_i18n() -> &'static HashMap<&'static str, HashMap<&'static str, &'static s I18N.get_or_init(init_i18n) } -pub fn lang(lang_id: &str, message_id: &'static str) -> &'static str { +pub fn lang(lang_id: &str, message_id: &str) -> &'static str { get_i18n() .get(lang_id) .and_then(|map| map.get(message_id)) diff --git a/i18n/src/message_ids.rs b/i18n/src/message_ids.rs index bde7bc9..f90383b 100644 --- a/i18n/src/message_ids.rs +++ b/i18n/src/message_ids.rs @@ -1,5 +1,11 @@ -pub const HELLO: &str = "hello"; -pub const ACCOUNT_DISABLED: &str = "accout is disabled"; -pub const ACCOUNT_NO_PERMISSION: &str = "account has no permission"; -pub const INCORRECT_USERNAME_OR_PASSWORD: &str = "Incorrect username or password"; -pub const INVALID_TOKEN: &str = "invalid token"; +pub const HELLO: &str = "HELLO"; +pub const ACCOUNT_DISABLED: &str = "ACCOUNT_DISABLED"; +pub const ACCOUNT_NO_PERMISSION: &str = "ACCOUNT_NO_PERMISSION"; +pub const INCORRECT_USERNAME_OR_PASSWORD: &str = "INCORRECT_USERNAME_OR_PASSWORD"; +pub const INVALID_TOKEN: &str = "INVALID_TOKEN"; + +pub const VALIDATE_FEEDBACK_CONTENT_REQUIRED: &'static str = "VALIDATE_FEEDBACK_CONTENT_REQUIRED"; +pub const VALIDATE_ACCOUNT_NAME_REQUIRED: &'static str = "VALIDATE_ACCOUNT_NAME_REQUIRED"; +pub const VALIDATE_ACCOUNT_PASSWORD_REQUIRED: &'static str = "VALIDATE_ACCOUNT_PASSWORD_REQUIRED"; +pub const VALIDATE_ACCOUNT_ID_TOKEN_REQUIRED: &'static str = "VALIDATE_ACCOUNT_ID_TOKEN_REQUIRED"; +pub const VALIDATE_ACCOUNT_LANG_TAG_REQUIRED: &'static str = "VALIDATE_ACCOUNT_LANG_TAG_REQUIRED"; \ No newline at end of file diff --git a/i18n/src/zh_cn.rs b/i18n/src/zh_cn.rs index a24e9f6..9214d95 100644 --- a/i18n/src/zh_cn.rs +++ b/i18n/src/zh_cn.rs @@ -3,7 +3,7 @@ use std::collections::HashMap; use lazy_static::lazy_static; use crate::message_ids::{ - ACCOUNT_DISABLED, ACCOUNT_NO_PERMISSION, HELLO, INCORRECT_USERNAME_OR_PASSWORD, INVALID_TOKEN, + ACCOUNT_DISABLED, ACCOUNT_NO_PERMISSION, HELLO, INCORRECT_USERNAME_OR_PASSWORD, INVALID_TOKEN, VALIDATE_ACCOUNT_ID_TOKEN_REQUIRED, VALIDATE_ACCOUNT_LANG_TAG_REQUIRED, VALIDATE_ACCOUNT_NAME_REQUIRED, VALIDATE_ACCOUNT_PASSWORD_REQUIRED, VALIDATE_FEEDBACK_CONTENT_REQUIRED }; pub const LANGUAGE_ID: &str = "zh_CN"; @@ -16,6 +16,12 @@ lazy_static! { map.insert(ACCOUNT_NO_PERMISSION, "账户无权限"); map.insert(INCORRECT_USERNAME_OR_PASSWORD, "用户名或密码错误"); map.insert(INVALID_TOKEN, "无效令牌"); + + map.insert(VALIDATE_FEEDBACK_CONTENT_REQUIRED, "反馈内容不能为空"); + map.insert(VALIDATE_ACCOUNT_NAME_REQUIRED, "用户名称不能为空"); + map.insert(VALIDATE_ACCOUNT_PASSWORD_REQUIRED, "密码不能为空"); + map.insert(VALIDATE_ACCOUNT_ID_TOKEN_REQUIRED, "用户ID Token不能为空"); + map.insert(VALIDATE_ACCOUNT_LANG_TAG_REQUIRED, "用户语言标识不能为空"); map }; } diff --git a/library/src/res/validator.rs b/library/src/res/validator.rs index 838cf25..c85df7e 100644 --- a/library/src/res/validator.rs +++ b/library/src/res/validator.rs @@ -1,8 +1,9 @@ +use i18n::message; use validator::Validate; use super::response::{ResData, ResErr, ResResult}; -pub fn validate_params(params: &impl Validate, _local: &str) -> ResResult> { +pub fn validate_params(params: &impl Validate, local: &str) -> ResResult> { let validate_err = params.validate(); match validate_err { Ok(_) => Result::Ok(ResData::none()), @@ -14,8 +15,7 @@ pub fn validate_params(params: &impl Validate, _local: &str) -> ResResult ResResult ResResult { err.iter().for_each(|e| { let msg = e.message.clone().unwrap_or_default(); - let msg_str = msg.to_string(); - errors.push(msg_str) + errors.push(message!(local, msg.trim())) }); }, }; diff --git a/service/src/account.rs b/service/src/account.rs index ce2bcee..b59ec7c 100644 --- a/service/src/account.rs +++ b/service/src/account.rs @@ -15,9 +15,9 @@ use library::token::{generate_refresh_token, generate_token}; use library::{db, token}; pub async fn authenticate_google( - context: Context, req: AuthenticateGooleAccountReq, ) -> ResResult> { + let lang_tag = req.lang_tag.unwrap(); let verify_result = GOOGLE_SOCIAL .verify_id_token(&req.id_token.unwrap()) .await @@ -47,7 +47,7 @@ pub async fn authenticate_google( tracing::info!("账户已存在, {:?}", account); if account.disable_time > Utc::now() { tracing::error!("账户已禁用"); - return Err(ResErr::system(message!(context.get_lang_id(), ACCOUNT_DISABLED))); + return Err(ResErr::system(message!(&lang_tag, ACCOUNT_DISABLED))); } account } diff --git a/service/src/feedback.rs b/service/src/feedback.rs index 706f68b..6901913 100644 --- a/service/src/feedback.rs +++ b/service/src/feedback.rs @@ -1,5 +1,6 @@ use domain::dto::feedback::FeedbackAdd; use domain::entities::feedback::Feedback; +use library::context::Context; use library::db; use library::res::pageable::Pageable; use library::res::response::{ResData, ResResult}; @@ -26,9 +27,13 @@ async fn get_feedback_count() -> i64 { } /// 添加反馈信息 -pub async fn add_feedback(req: FeedbackAdd) -> ResResult> { +pub async fn add_feedback( + context: Context, + req: FeedbackAdd +) -> ResResult> { + let account = context.account; match Feedback::add_feedback(&mut Feedback{ - user_id: req.user_id.unwrap(), + user_id: account.id.clone(), content: req.content.unwrap(), ..Default::default() }, db!()).await { diff --git a/service/src/sys_account.rs b/service/src/sys_account.rs index a6b15ca..40aa894 100644 --- a/service/src/sys_account.rs +++ b/service/src/sys_account.rs @@ -12,22 +12,21 @@ use i18n::{ }; use library::{ cache::account_cache::{CacheAccount, LOGIN_CACHE}, - context::Context, db, res::response::{ResData, ResErr, ResResult}, token::{generate_refresh_token, generate_token}, }; pub async fn authenticate_with_password( - context: Context, req: AuthenticateWithPassword, ) -> ResResult> { + let lang_tag = req.lang_tag.unwrap(); let account = Account::find_with_password(req.username.unwrap(), req.password.unwrap(), db!()).await?; if account.is_none() { tracing::info!("登录用户失败,用户查询为空"); return Err(ResErr::params(message!( - context.get_lang_id(), + &lang_tag, INCORRECT_USERNAME_OR_PASSWORD ))); } @@ -35,14 +34,14 @@ pub async fn authenticate_with_password( if account.disable_time > Utc::now() { tracing::error!("账户已禁用"); return Err(ResErr::auth(message!( - context.get_lang_id(), + &lang_tag, ACCOUNT_DISABLED ))); } if !account.role.is_admin() { tracing::error!("账户不是管理员,无权限"); return Err(ResErr::perm(message!( - context.get_lang_id(), + &lang_tag, ACCOUNT_NO_PERMISSION ))); }