From 461edb0f25b4fe04913a476c577461297d0f6220 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E8=BF=90=E5=AE=B6?= Date: Fri, 27 Sep 2024 15:11:45 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0sqlx=E4=BA=8B=E5=8A=A1?= =?UTF-8?q?=EF=BC=8C=E5=A4=87=E6=B3=A8=EF=BC=9A=E5=A6=82=E6=9E=9C=E5=8F=AA?= =?UTF-8?q?=E6=B6=89=E5=8F=8A=E5=88=B0=E5=8D=95=E6=AC=A1=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E5=8F=98=E6=9B=B4=E6=93=8D=E4=BD=9C=EF=BC=8C=E5=8F=AF=E4=BB=A5?= =?UTF-8?q?=E4=B8=8D=E4=BD=BF=E7=94=A8=E4=BA=8B=E5=8A=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cargo.lock | 4 +- domain/src/entities/account.rs | 77 ++++++++++++++++------- domain/src/entities/feedback.rs | 59 +++++++++++++---- server/src/service/account_service.rs | 27 ++++++-- server/src/service/feedback_service.rs | 36 +++++++---- server/src/service/sys_account_service.rs | 18 +++++- 6 files changed, 164 insertions(+), 57 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 00e8dc3..f6e93a9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2900,9 +2900,9 @@ checksum = "e4259d9d4425d9f0661581b804cb85fe66a4c631cadd8f490d1c13a35d5d9291" [[package]] name = "unicode-segmentation" -version = "1.11.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" [[package]] name = "unicode_categories" diff --git a/domain/src/entities/account.rs b/domain/src/entities/account.rs index 7b75e6b..32f1d99 100644 --- a/domain/src/entities/account.rs +++ b/domain/src/entities/account.rs @@ -1,8 +1,8 @@ use std::fmt::Display; use chrono::{DateTime, Utc}; -use sqlx::{Error, PgPool}; use sqlx::types::{chrono, JsonValue}; +use sqlx::{Error, PgPool, Postgres, Transaction}; #[derive(Debug, PartialEq, Clone)] pub enum Role { @@ -81,15 +81,18 @@ pub struct Account { } impl Account { - - pub async fn find_by_apple_id(apple_id: &str, db_pool: &PgPool) -> Result, Error> { + pub async fn find_by_apple_id( + apple_id: &str, + db_pool: &PgPool, + ) -> Result, Error> { match sqlx::query_as!( Account, r#"select * from account where apple_id = $1"#, apple_id ) - .fetch_one(db_pool) - .await { + .fetch_one(db_pool) + .await + { Ok(account) => { return Ok(Some(account)); } @@ -103,14 +106,18 @@ impl Account { } } - pub async fn find_by_custom_id(custom_id: &str, db_pool: &PgPool) -> Result, Error> { + pub async fn find_by_custom_id( + custom_id: &str, + db_pool: &PgPool, + ) -> Result, Error> { match sqlx::query_as!( Account, r#"select * from account where custom_id = $1"#, custom_id ) - .fetch_one(db_pool) - .await { + .fetch_one(db_pool) + .await + { Ok(account) => { return Ok(Some(account)); } @@ -124,14 +131,18 @@ impl Account { } } - pub async fn find_by_facebook_id(facebook_id: &str, db_pool: &PgPool) -> Result, Error> { + pub async fn find_by_facebook_id( + facebook_id: &str, + db_pool: &PgPool, + ) -> Result, Error> { match sqlx::query_as!( Account, r#"select * from account where facebook_id = $1"#, facebook_id ) - .fetch_one(db_pool) - .await { + .fetch_one(db_pool) + .await + { Ok(account) => { return Ok(Some(account)); } @@ -144,14 +155,19 @@ impl Account { } } } - pub async fn find_by_google_id(google_id: &str, db_pool: &PgPool) -> Result, Error> { + + pub async fn find_by_google_id( + google_id: &str, + db_pool: &PgPool, + ) -> Result, Error> { match sqlx::query_as!( Account, r#"select * from account where google_id = $1"#, google_id ) - .fetch_one(db_pool) - .await { + .fetch_one(db_pool) + .await + { Ok(account) => { return Ok(Some(account)); } @@ -165,7 +181,10 @@ impl Account { } } - pub async fn save_google_account(&self, db_pool: &PgPool) -> Result { + pub async fn save_google_account( + &self, + transaction: &mut Transaction<'_, Postgres>, + ) -> Result { sqlx::query_as!( Account, r#" @@ -179,10 +198,16 @@ impl Account { self.email.clone().unwrap(), self.display_name.clone().unwrap(), self.avatar_url.clone().unwrap() - ).fetch_one(db_pool).await + ) + .fetch_one(&mut **transaction) + .await } - pub async fn find_with_password(username: String, password: String, db_pool: &PgPool) -> Result, Error> { + pub async fn find_with_password( + username: String, + password: String, + db_pool: &PgPool, + ) -> Result, Error> { match sqlx::query_as!( Account, r#" @@ -190,7 +215,10 @@ impl Account { "#, username, password.as_bytes().to_vec(), - ).fetch_one(db_pool).await { + ) + .fetch_one(db_pool) + .await + { Ok(account) => { return Ok(Some(account)); } @@ -204,7 +232,10 @@ impl Account { } } - pub async fn add_account(&self, db_pool: &PgPool) -> Result, Error> { + pub async fn add_account( + &self, + transaction: &mut Transaction<'_, Postgres>, + ) -> Result, Error> { match sqlx::query_as!( Account, r#" @@ -219,7 +250,10 @@ impl Account { self.role.to_string(), self.wallet, self.metadata - ).fetch_one(db_pool).await { + ) + .fetch_one(&mut **transaction) + .await + { Ok(account) => { return Ok(Some(account)); } @@ -232,5 +266,4 @@ impl Account { } } } - -} \ No newline at end of file +} diff --git a/domain/src/entities/feedback.rs b/domain/src/entities/feedback.rs index 6a42c94..f263b57 100644 --- a/domain/src/entities/feedback.rs +++ b/domain/src/entities/feedback.rs @@ -1,8 +1,8 @@ +use crate::db_result::CountResult; use chrono::NaiveDateTime; use serde::{Deserialize, Serialize}; -use sqlx::PgPool; use sqlx::types::chrono; -use crate::db_result::CountResult; +use sqlx::{PgPool, Postgres, Transaction}; #[derive(Debug, Clone, Deserialize, Default, Serialize)] pub struct Feedback { @@ -13,22 +13,31 @@ pub struct Feedback { } impl Feedback { - pub async fn search_feedback(page: i64, page_size: i64, db_pool: &PgPool) -> Result, sqlx::Error> { + pub async fn search_feedback( + page: i64, + page_size: i64, + db_pool: &PgPool, + ) -> Result, sqlx::Error> { sqlx::query_as!( Feedback, r#"select id, user_id, content, created_at from feedback limit $1 offset $2"#, - page_size, page - ).fetch_all(db_pool).await + page_size, + page + ) + .fetch_all(db_pool) + .await } pub async fn count_feedback(db_pool: &PgPool) -> Result { - sqlx::query_as!( - CountResult, - r#"select count(*) from feedback"#, - ).fetch_one(db_pool).await + sqlx::query_as!(CountResult, r#"select count(*) from feedback"#,) + .fetch_one(db_pool) + .await } - pub async fn add_feedback(feedback: &mut Feedback, db_pool: &PgPool) -> Result { + pub async fn add_feedback( + feedback: &mut Feedback, + transaction: &mut Transaction<'_, Postgres>, + ) -> Result { feedback.created_at = chrono::Local::now().naive_local(); sqlx::query_as!( Feedback, @@ -40,6 +49,32 @@ impl Feedback { feedback.user_id, feedback.content, feedback.created_at - ).fetch_one(db_pool).await + ) + .fetch_one(&mut **transaction) + .await } -} \ No newline at end of file + + // pub async fn add_feedback<'e, 'a, E>( + // feedback: &mut Feedback, + // db_pool: &PgPool, + // ) -> Result + // where + // E: 'e + Executor<'a, Database = Postgres>, + // { + // let mut transaction = db_pool.begin().await?; + // feedback.created_at = chrono::Local::now().naive_local(); + // sqlx::query_as!( + // Feedback, + // r#"insert into feedback + // (user_id, content, created_at) + // values + // ($1, $2, $3) returning * + // "#, + // feedback.user_id, + // feedback.content, + // feedback.created_at + // ) + // .fetch_one(&mut *transaction) + // .await + // } +} diff --git a/server/src/service/account_service.rs b/server/src/service/account_service.rs index 4f9d4ef..6bdfbda 100644 --- a/server/src/service/account_service.rs +++ b/server/src/service/account_service.rs @@ -26,11 +26,12 @@ pub async fn authenticate_google( ErrPerm(None) })?; + let mut transaction = db!().begin().await?; let account = Account::find_by_google_id(&verify_result.aud, db!()).await?; let account = match account { None => { tracing::info!("账户不存在, {:?}", verify_result); - Account::save_google_account( + match Account::save_google_account( &Account { username: verify_result.name, google_id: Some(verify_result.aud), @@ -39,16 +40,29 @@ pub async fn authenticate_google( avatar_url: Some(verify_result.picture), ..Default::default() }, - db!(), + &mut transaction, ) - .await? + .await { + Ok(account) => { + transaction.commit().await?; + account + }, + Err(err) => { + transaction.rollback().await?; + tracing::error!(error = ?err, "保存Google用户失败"); + return Err(ResErr::service("保存Google用户失败")); + } + } } Some(account) => { tracing::info!("账户已存在, {:?}", account); if let Some(disable_time) = account.disable_time { if disable_time > Utc::now() { tracing::error!("账户已禁用"); - return Err(ResErr::service(message!(context.get_lang_tag(), MessageId::AccountDisabled))); + return Err(ResErr::service(message!( + context.get_lang_tag(), + MessageId::AccountDisabled + ))); } } @@ -89,7 +103,10 @@ pub async fn refresh_token( let account = context.account.clone(); if token::verify_refresh_token(&refresh_token).is_err() { - return Err(ResErr::params(message!(context.get_lang_tag(), MessageId::InvalidToken))); + return Err(ResErr::params(message!( + context.get_lang_tag(), + MessageId::InvalidToken + ))); } let refresh_token = RefreshTokenResult { diff --git a/server/src/service/feedback_service.rs b/server/src/service/feedback_service.rs index 147f18b..a9fbb83 100644 --- a/server/src/service/feedback_service.rs +++ b/server/src/service/feedback_service.rs @@ -8,8 +8,8 @@ use library::model::response::ResResult; /// 获取反馈信息列表 pub async fn get_feedback_list_by_page( context: Context, - page: i64, - page_size: i64 + page: i64, + page_size: i64, ) -> ResResult { if !context.account.role.is_admin() { tracing::error!("非管理员用户,无法获取反馈信息列表"); @@ -21,7 +21,12 @@ pub async fn get_feedback_list_by_page( return Ok(FeedbackPageable::empty(page, page_size)); } let total = get_feedback_count().await; - Ok(FeedbackPageable::new(feedback_list.unwrap(), total, page, page_size)) + Ok(FeedbackPageable::new( + feedback_list.unwrap(), + total, + page, + page_size, + )) } /// 获取反馈信息总数 @@ -35,24 +40,29 @@ async fn get_feedback_count() -> i64 { } /// 添加反馈信息 -pub async fn add_feedback( - context: Context, - 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: account.id.clone(), - content: req.content.unwrap(), - ..Default::default() - }, db!()).await { + let mut transaction = db!().begin().await?; + match Feedback::add_feedback( + &mut Feedback { + user_id: account.id.clone(), + content: req.content.unwrap(), + ..Default::default() + }, + &mut transaction, + ) + .await + { Ok(feedback) => { + transaction.commit().await?; tracing::info!("添加反馈成功: {:?}", feedback) } Err(err) => { + transaction.rollback().await?; tracing::error!(error = ?err, "添加反馈信息失败"); return Err(library::model::response::ResErr::ErrService(None)); } } Ok(()) -} \ No newline at end of file +} diff --git a/server/src/service/sys_account_service.rs b/server/src/service/sys_account_service.rs index 4dd08bf..f2fa130 100644 --- a/server/src/service/sys_account_service.rs +++ b/server/src/service/sys_account_service.rs @@ -74,16 +74,28 @@ pub async fn authenticate_with_password( /// 仅仅用于管理员维护,不对外暴露接口 pub async fn add_account() -> ResResult<()> { - let account = Account::add_account( + let mut transaction = db!().begin().await?; + let account = match Account::add_account( &Account { username: "admin".to_string(), password: Some("123456".as_bytes().to_vec()), role: Role::Admin, ..Default::default() }, - db!(), + &mut transaction, ) - .await?; + .await { + Ok(account) => { + transaction.commit().await?; + account + }, + Err(err) => { + transaction.rollback().await?; + tracing::error!(error = ?err, "添加用户失败"); + return Err(ResErr::service("添加用户失败")); + } + }; + if account.is_none() { tracing::error!("添加用户失败"); return Err(ResErr::service("添加用户失败"));