添加用户表的初始化 SQL 脚本,重构用户模型,更新用户输入模型,优化用户存储库和服务以支持新用户注册功能
This commit is contained in:
parent
c49734430b
commit
ea98d5625a
29
init.sql
Normal file
29
init.sql
Normal file
@ -0,0 +1,29 @@
|
||||
CREATE TABLE users (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
account VARCHAR(255) UNIQUE NOT NULL,
|
||||
name VARCHAR(255) NOT NULL,
|
||||
birth DATE,
|
||||
email VARCHAR(255),
|
||||
password VARCHAR(255) NOT NULL,
|
||||
phone VARCHAR(20),
|
||||
status ENUM(
|
||||
'active',
|
||||
'inactive',
|
||||
'suspended',
|
||||
'deleted',
|
||||
'locked',
|
||||
'pending verfication'
|
||||
) DEFAULT 'active',
|
||||
created_time DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
INSERT INTO
|
||||
test_server.users (id, account, name, birth, password)
|
||||
VALUES
|
||||
(0, '123', 'hyh', '2000-0-03', '1');
|
||||
|
||||
INSERT INTO
|
||||
test_server.users (account, name, password)
|
||||
VALUES
|
||||
('123', 'hyh', '1');
|
||||
@ -1,8 +1,13 @@
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||
pub struct User {
|
||||
pub id: Option<i32>,
|
||||
pub name: String,
|
||||
pub age: i32,
|
||||
pub email: String,
|
||||
pub password: String,
|
||||
pub account: Option<String>,
|
||||
pub name: Option<String>,
|
||||
pub birth: Option<String>,
|
||||
pub email: Option<String>,
|
||||
pub password: Option<String>,
|
||||
pub phone: Option<String>,
|
||||
pub status: Option<String>,
|
||||
pub created_time: Option<String>,
|
||||
pub updated_time: Option<String>,
|
||||
}
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||
pub struct UserInput {
|
||||
pub account: Option<String>,
|
||||
pub name: Option<String>,
|
||||
pub age: Option<i32>,
|
||||
pub email: Option<String>,
|
||||
pub password: Option<String>,
|
||||
}
|
||||
|
||||
@ -1,10 +1,11 @@
|
||||
use crate::models::user::User;
|
||||
use mysql::prelude::Queryable;
|
||||
use mysql::{params, Error as MysqlError};
|
||||
use r2d2::{Error as R2D2Error, Pool};
|
||||
use r2d2_mysql::MySqlConnectionManager;
|
||||
use thiserror::Error;
|
||||
|
||||
use crate::models::user::User;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum UserRepositoryError {
|
||||
#[error("mysql error: {0}")]
|
||||
@ -26,22 +27,57 @@ impl UserRepository {
|
||||
/**
|
||||
* 新建用户
|
||||
*/
|
||||
pub fn create_user(&self, user: &User) -> Result<(), UserRepositoryError> {
|
||||
let mut conn = self.pool.get().unwrap();
|
||||
let sql = r"INSERT INTO users (id, name, age, email, password) VALUES (:id, :name, :age, :email, :password)";
|
||||
pub fn insert_user(
|
||||
&self,
|
||||
account: &str,
|
||||
name: &str,
|
||||
password: &str,
|
||||
) -> Result<(), UserRepositoryError> {
|
||||
let mut conn = self.pool.get().map_err(UserRepositoryError::PoolError)?;
|
||||
let sql = "INSERT INTO users (account, name, password) VALUES (:account, :name, :password)";
|
||||
conn.exec_drop(
|
||||
sql,
|
||||
params! {
|
||||
"id" => &user.id,
|
||||
"name" => &user.name,
|
||||
"age" => &user.age,
|
||||
"email" => &user.email,
|
||||
"password" => &user.password,
|
||||
},
|
||||
)?;
|
||||
params! {"account" => account, "name" => name, "password" => password},
|
||||
)
|
||||
.map_err(UserRepositoryError::MySqlError)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据account查询用户
|
||||
*/
|
||||
pub fn query_user_by_account(
|
||||
&self,
|
||||
account: &str,
|
||||
) -> Result<Option<User>, UserRepositoryError> {
|
||||
let mut conn = self
|
||||
.pool
|
||||
.get()
|
||||
.map_err(|e| UserRepositoryError::PoolError(e))?;
|
||||
|
||||
let sql = "SELECT account, name FROM users WHERE account = :account";
|
||||
|
||||
match conn.exec_first(sql, params! {"account" => account}) {
|
||||
Ok(Some(row)) => {
|
||||
let (account, name) = mysql::from_row(row);
|
||||
Ok(Some(User {
|
||||
id: None,
|
||||
name,
|
||||
password: None,
|
||||
account,
|
||||
birth: None,
|
||||
email: None,
|
||||
phone: None,
|
||||
status: None,
|
||||
created_time: None,
|
||||
updated_time: None,
|
||||
}))
|
||||
}
|
||||
Ok(None) => Ok(None),
|
||||
Err(e) => Err(UserRepositoryError::MySqlError(e)),
|
||||
}
|
||||
}
|
||||
|
||||
// /**
|
||||
// * 删除用户
|
||||
// */
|
||||
@ -89,25 +125,11 @@ impl UserRepository {
|
||||
// )
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * 根据ID查询用户
|
||||
// */
|
||||
// pub fn query_user_by_id(&mut self, id: i32) -> Result<Option<User>, mysql::Error> {
|
||||
// let mut conn = self.pool.get().unwrap();
|
||||
// let result: Option<User> = conn.exec_first(
|
||||
// "SELECT id, name, age, email, password FROM users WHERE id = :id",
|
||||
// params! {
|
||||
// "id" => id,
|
||||
// },
|
||||
// )?;
|
||||
// Ok(result)
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * 根据用户名查询用户
|
||||
// */
|
||||
// pub fn query_user_by_name(&mut self, name: &str) -> Result<Option<User>, mysql::Error> {
|
||||
// let mut conn = self.pool.get().unwrap();
|
||||
// pub fn query_user_by_name(&self, name: &str) -> Result<Option<User>, UserRepositoryError> {
|
||||
// let mut conn = self.pool.get().map_err(UserRepositoryError::PoolError)?;
|
||||
// conn.exec_first(
|
||||
// "SELECT id, name, age, email, password FROM users WHERE name = :name",
|
||||
// params! {
|
||||
@ -119,8 +141,9 @@ impl UserRepository {
|
||||
// /**
|
||||
// * 根据邮箱查询用户
|
||||
// */
|
||||
// pub fn query_user_by_email(&mut self, email: &str) -> Result<Option<User>, mysql::Error> {
|
||||
// let mut conn = self.pool.get().unwrap();
|
||||
// pub fn query_user_by_email(&self, email: &str) -> Result<Option<User>, UserRepositoryError> {
|
||||
// let mut conn = self.pool.get().map_err(UserRepositoryError::PoolError)?;
|
||||
|
||||
// conn.exec_first(
|
||||
// "SELECT id, name, age, email, password FROM users WHERE email = :email",
|
||||
// params! {
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
use crate::{
|
||||
models::{user::User, user_input::UserInput},
|
||||
models::user_input::UserInput,
|
||||
repositories::user_repository::{UserRepository, UserRepositoryError},
|
||||
};
|
||||
use bcrypt::{hash, DEFAULT_COST};
|
||||
@ -14,6 +14,9 @@ pub enum UserServiceError {
|
||||
#[error("Missing field: {0}")]
|
||||
MissingField(&'static str),
|
||||
|
||||
#[error("User already exists")]
|
||||
UserAlreadyExists,
|
||||
|
||||
#[error("Password hashing failed: {0}")]
|
||||
HashError(#[from] bcrypt::BcryptError),
|
||||
}
|
||||
@ -31,35 +34,28 @@ impl UserService {
|
||||
* 新建用户
|
||||
*/
|
||||
pub fn create_user(&self, user: &UserInput) -> Result<(), UserServiceError> {
|
||||
let account = user
|
||||
.account
|
||||
.as_ref()
|
||||
.ok_or(UserServiceError::MissingField("account"))?
|
||||
.to_string();
|
||||
let name = user
|
||||
.name
|
||||
.as_ref()
|
||||
.ok_or(UserServiceError::MissingField("name"))?
|
||||
.to_string();
|
||||
let age = user
|
||||
.age
|
||||
.as_ref()
|
||||
.ok_or(UserServiceError::MissingField("age"))?;
|
||||
let email = user
|
||||
.email
|
||||
.as_ref()
|
||||
.ok_or(UserServiceError::MissingField("email"))?
|
||||
.to_string();
|
||||
let password = user
|
||||
.password
|
||||
.as_ref()
|
||||
.ok_or(UserServiceError::MissingField("password"))?
|
||||
.to_string();
|
||||
|
||||
let mut new_user = User {
|
||||
id: Some(0),
|
||||
name,
|
||||
age: *age,
|
||||
email,
|
||||
password: hash(password, DEFAULT_COST).unwrap(),
|
||||
};
|
||||
if self.repository.query_user_by_account(&account)?.is_some() {
|
||||
return Err(UserServiceError::UserAlreadyExists);
|
||||
}
|
||||
|
||||
self.repository.create_user(&mut new_user)?;
|
||||
self.repository
|
||||
.insert_user(&account, &name, &hash(password, DEFAULT_COST).unwrap())?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user