Browse Source
many changes - mainly moving to refined newtypes
many changes - mainly moving to refined newtypes
other changes - add dependencies for implementing refined newtypes - derive-more/validators rename Plain logger format to Pretty rename regexs package to regexmain
Rohan Sircar
3 years ago
14 changed files with 573 additions and 287 deletions
-
2.env
-
397Cargo.lock
-
9Cargo.toml
-
20README.md
-
50src/actions/users.rs
-
6src/errors/domain_error.rs
-
6src/lib.rs
-
2src/main.rs
-
4src/models/api_response.rs
-
131src/models/users.rs
-
99src/routes/users.rs
-
128src/services/user_service.rs
-
4src/utils.rs
-
2src/utils/regex.rs
@ -1,27 +1,130 @@ |
|||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||
|
|
||||
use crate::schema::users;
|
use crate::schema::users;
|
||||
use crate::utils::regexs;
|
|
||||
use validator_derive::*;
|
|
||||
|
use crate::utils::regex;
|
||||
|
use derive_more::{Display, Into};
|
||||
|
use std::convert::TryFrom;
|
||||
|
use std::{convert::TryInto, str::FromStr};
|
||||
|
use validators::prelude::*;
|
||||
|
|
||||
#[derive(Debug, Clone, Queryable, Identifiable, Deserialize)]
|
|
||||
|
#[derive(
|
||||
|
Debug,
|
||||
|
Clone,
|
||||
|
Eq,
|
||||
|
Hash,
|
||||
|
PartialEq,
|
||||
|
Deserialize,
|
||||
|
Display,
|
||||
|
Into,
|
||||
|
Serialize,
|
||||
|
DieselNewType,
|
||||
|
)]
|
||||
|
#[serde(try_from = "u32", into = "u32")]
|
||||
|
pub struct UserId(i32);
|
||||
|
impl From<UserId> for u32 {
|
||||
|
fn from(s: UserId) -> u32 {
|
||||
|
//this should be safe to unwrap since our newtype
|
||||
|
//does not allow negative values
|
||||
|
s.0.try_into().unwrap()
|
||||
|
}
|
||||
|
}
|
||||
|
|
||||
|
impl FromStr for UserId {
|
||||
|
type Err = String;
|
||||
|
|
||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
|
if let Ok(num) = s.parse::<u32>() {
|
||||
|
(num as u32)
|
||||
|
.try_into()
|
||||
|
.map_err(|err| {
|
||||
|
format!("error while converting user_id: {}", err)
|
||||
|
})
|
||||
|
.map(UserId)
|
||||
|
} else {
|
||||
|
Err("negative values are not allowed".to_owned())
|
||||
|
}
|
||||
|
}
|
||||
|
}
|
||||
|
|
||||
|
impl TryFrom<u32> for UserId {
|
||||
|
type Error = String;
|
||||
|
fn try_from(value: u32) -> Result<Self, Self::Error> {
|
||||
|
value
|
||||
|
.try_into()
|
||||
|
.map_err(|err| format!("error while converting user_id: {}", err))
|
||||
|
.map(UserId)
|
||||
|
}
|
||||
|
}
|
||||
|
#[derive(Validator, Debug, Clone, DieselNewType)]
|
||||
|
#[validator(regex(regex::USERNAME_REG))]
|
||||
|
pub struct Username(String);
|
||||
|
impl Username {
|
||||
|
pub fn as_str(&self) -> &str {
|
||||
|
&self.0
|
||||
|
}
|
||||
|
}
|
||||
|
#[derive(Validator, Debug, Clone, DieselNewType)]
|
||||
|
#[validator(line(char_length(max = 200)))]
|
||||
|
pub struct Password(String);
|
||||
|
|
||||
|
impl Password {
|
||||
|
pub fn as_str(&self) -> &str {
|
||||
|
&self.0
|
||||
|
}
|
||||
|
}
|
||||
|
|
||||
|
#[derive(Debug, Clone, Deserialize, Serialize, Queryable, Identifiable)]
|
||||
|
#[table_name = "users"]
|
||||
pub struct User {
|
pub struct User {
|
||||
pub id: i32,
|
|
||||
pub name: String,
|
|
||||
pub password: String,
|
|
||||
|
pub id: UserId,
|
||||
|
pub name: Username,
|
||||
|
#[serde(skip_serializing)]
|
||||
|
pub password: Password,
|
||||
pub created_at: chrono::NaiveDateTime,
|
pub created_at: chrono::NaiveDateTime,
|
||||
}
|
}
|
||||
|
|
||||
#[derive(Debug, Clone, Insertable, Deserialize, Validate)]
|
|
||||
|
#[derive(Debug, Clone, Insertable, Deserialize)]
|
||||
#[table_name = "users"]
|
#[table_name = "users"]
|
||||
pub struct NewUser {
|
pub struct NewUser {
|
||||
#[validate(regex = "regexs::USERNAME_REG", length(min = 4, max = 10))]
|
|
||||
pub name: String,
|
|
||||
pub password: String,
|
|
||||
|
pub name: Username,
|
||||
|
#[serde(skip_serializing)]
|
||||
|
pub password: Password,
|
||||
}
|
}
|
||||
|
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Queryable)]
|
|
||||
pub struct UserDto {
|
|
||||
pub name: String,
|
|
||||
pub registration_date: chrono::NaiveDateTime,
|
|
||||
|
#[cfg(test)]
|
||||
|
mod test {
|
||||
|
use super::*;
|
||||
|
#[test]
|
||||
|
fn user_model_refinement_test() {
|
||||
|
//yes I had been watching a lot of star wars lately
|
||||
|
let mb_user = serde_json::from_str::<User>(
|
||||
|
r#"{"id":1,"name":"chewbacca","password":"aeqfq3fq","created_at":"2021-05-12T12:37:56"}"#,
|
||||
|
);
|
||||
|
// println!("{:?}", mb_user);
|
||||
|
assert_eq!(mb_user.is_ok(), true);
|
||||
|
let mb_user = serde_json::from_str::<User>(
|
||||
|
r#"{"id":1,"name":"chew-bacca","password":"aeqfq3fq","created_at":"2021-05-12T12:37:56"}"#,
|
||||
|
);
|
||||
|
assert_eq!(mb_user.is_ok(), true);
|
||||
|
let mb_user = serde_json::from_str::<User>(
|
||||
|
r#"{"id":1,"name":"chew.bacca","password":"aeqfq3fq","created_at":"2021-05-12T12:37:56"}"#,
|
||||
|
);
|
||||
|
assert_eq!(mb_user.is_ok(), false);
|
||||
|
let mb_user = serde_json::from_str::<User>(
|
||||
|
r#"{"id":-1,"name":"chewbacca","password":"aeqfq3fq","created_at":"2021-05-12T12:37:56"}"#,
|
||||
|
);
|
||||
|
assert_eq!(mb_user.is_ok(), false);
|
||||
|
let mb_user = serde_json::from_str::<User>(
|
||||
|
r#"{"id":1,"name":"ch","password":"aeqfq3fq","created_at":"2021-05-12T12:37:56"}"#,
|
||||
|
);
|
||||
|
assert_eq!(mb_user.is_ok(), false);
|
||||
|
let mb_user = serde_json::from_str::<User>(
|
||||
|
r#"{"id":1,"name":"chaegw;eaef","password":"aeqfq3fq","created_at":"2021-05-12T12:37:56"}"#,
|
||||
|
);
|
||||
|
assert_eq!(mb_user.is_ok(), false);
|
||||
|
let mb_user = serde_json::from_str::<User>(
|
||||
|
r#"{"id":1,"name":"chaegw_eaef","password":"aeqfq3fq","created_at":"2021-05-12T12:37:56"}"#,
|
||||
|
);
|
||||
|
assert_eq!(mb_user.is_ok(), false);
|
||||
|
}
|
||||
}
|
}
|
@ -1,76 +1,76 @@ |
|||||
use crate::{actions, errors, models, types::DbPool};
|
|
||||
|
// use crate::{actions, errors, models, types::DbPool};
|
||||
|
|
||||
pub trait UserService {
|
|
||||
fn find_user_by_uid(
|
|
||||
&self,
|
|
||||
uid: i32,
|
|
||||
) -> Result<Option<models::UserDto>, errors::DomainError>;
|
|
||||
fn _find_user_by_name(
|
|
||||
&self,
|
|
||||
user_name: String,
|
|
||||
) -> Result<Option<models::UserDto>, errors::DomainError>;
|
|
||||
|
// pub trait UserService {
|
||||
|
// fn find_user_by_uid(
|
||||
|
// &self,
|
||||
|
// uid: i32,
|
||||
|
// ) -> Result<Option<models::UserDto>, errors::DomainError>;
|
||||
|
// fn _find_user_by_name(
|
||||
|
// &self,
|
||||
|
// user_name: String,
|
||||
|
// ) -> Result<Option<models::UserDto>, errors::DomainError>;
|
||||
|
|
||||
fn get_all(&self) -> Result<Vec<models::UserDto>, errors::DomainError>;
|
|
||||
|
// fn get_all(&self) -> Result<Vec<models::UserDto>, errors::DomainError>;
|
||||
|
|
||||
fn insert_new_user(
|
|
||||
&self,
|
|
||||
nu: models::NewUser,
|
|
||||
) -> Result<models::UserDto, errors::DomainError>;
|
|
||||
|
// fn insert_new_user(
|
||||
|
// &self,
|
||||
|
// nu: models::NewUser,
|
||||
|
// ) -> Result<models::UserDto, errors::DomainError>;
|
||||
|
|
||||
// fn woot(&self) -> i32;
|
|
||||
|
// // fn woot(&self) -> i32;
|
||||
|
|
||||
fn verify_password(
|
|
||||
&self,
|
|
||||
user_name: &str,
|
|
||||
given_password: &str,
|
|
||||
) -> Result<bool, errors::DomainError>;
|
|
||||
}
|
|
||||
|
// fn verify_password(
|
||||
|
// &self,
|
||||
|
// user_name: &str,
|
||||
|
// given_password: &str,
|
||||
|
// ) -> Result<bool, errors::DomainError>;
|
||||
|
// }
|
||||
|
|
||||
#[derive(Clone)]
|
|
||||
pub struct UserServiceImpl {
|
|
||||
pub pool: DbPool,
|
|
||||
}
|
|
||||
|
// #[derive(Clone)]
|
||||
|
// pub struct UserServiceImpl {
|
||||
|
// pub pool: DbPool,
|
||||
|
// }
|
||||
|
|
||||
impl UserService for UserServiceImpl {
|
|
||||
fn find_user_by_uid(
|
|
||||
&self,
|
|
||||
uid: i32,
|
|
||||
) -> Result<Option<models::UserDto>, errors::DomainError> {
|
|
||||
let conn = self.pool.get()?;
|
|
||||
actions::find_user_by_uid(uid, &conn)
|
|
||||
}
|
|
||||
|
// impl UserService for UserServiceImpl {
|
||||
|
// fn find_user_by_uid(
|
||||
|
// &self,
|
||||
|
// uid: i32,
|
||||
|
// ) -> Result<Option<models::UserDto>, errors::DomainError> {
|
||||
|
// let conn = self.pool.get()?;
|
||||
|
// actions::find_user_by_uid(uid, &conn)
|
||||
|
// }
|
||||
|
|
||||
fn _find_user_by_name(
|
|
||||
&self,
|
|
||||
user_name: String,
|
|
||||
) -> Result<Option<models::UserDto>, errors::DomainError> {
|
|
||||
let conn = self.pool.get()?;
|
|
||||
actions::_find_user_by_name(user_name, &conn)
|
|
||||
}
|
|
||||
|
// fn _find_user_by_name(
|
||||
|
// &self,
|
||||
|
// user_name: String,
|
||||
|
// ) -> Result<Option<models::UserDto>, errors::DomainError> {
|
||||
|
// let conn = self.pool.get()?;
|
||||
|
// actions::_find_user_by_name(user_name, &conn)
|
||||
|
// }
|
||||
|
|
||||
fn get_all(&self) -> Result<Vec<models::UserDto>, errors::DomainError> {
|
|
||||
let conn = self.pool.get()?;
|
|
||||
actions::get_all(&conn)
|
|
||||
}
|
|
||||
|
// fn get_all(&self) -> Result<Vec<models::UserDto>, errors::DomainError> {
|
||||
|
// let conn = self.pool.get()?;
|
||||
|
// actions::get_all(&conn)
|
||||
|
// }
|
||||
|
|
||||
fn insert_new_user(
|
|
||||
&self,
|
|
||||
nu: models::NewUser,
|
|
||||
) -> Result<models::UserDto, errors::DomainError> {
|
|
||||
let conn = self.pool.get()?;
|
|
||||
actions::insert_new_user(nu, &conn, Some(8))
|
|
||||
}
|
|
||||
|
// fn insert_new_user(
|
||||
|
// &self,
|
||||
|
// nu: models::NewUser,
|
||||
|
// ) -> Result<models::UserDto, errors::DomainError> {
|
||||
|
// let conn = self.pool.get()?;
|
||||
|
// actions::insert_new_user(nu, &conn, Some(8))
|
||||
|
// }
|
||||
|
|
||||
fn verify_password(
|
|
||||
&self,
|
|
||||
user_name: &str,
|
|
||||
given_password: &str,
|
|
||||
) -> Result<bool, errors::DomainError> {
|
|
||||
let conn = self.pool.get()?;
|
|
||||
actions::verify_password(user_name, given_password, &conn)
|
|
||||
}
|
|
||||
|
// fn verify_password(
|
||||
|
// &self,
|
||||
|
// user_name: &str,
|
||||
|
// given_password: &str,
|
||||
|
// ) -> Result<bool, errors::DomainError> {
|
||||
|
// let conn = self.pool.get()?;
|
||||
|
// actions::verify_password(user_name, given_password, &conn)
|
||||
|
// }
|
||||
|
|
||||
// async fn woot(&self) -> i32 {
|
|
||||
// 1
|
|
||||
// }
|
|
||||
}
|
|
||||
|
// // async fn woot(&self) -> i32 {
|
||||
|
// // 1
|
||||
|
// // }
|
||||
|
// }
|
@ -1,4 +1,4 @@ |
|||||
pub mod auth;
|
pub mod auth;
|
||||
pub mod regexs;
|
|
||||
|
pub mod regex;
|
||||
pub use self::auth::*;
|
pub use self::auth::*;
|
||||
pub use self::regexs::*;
|
|
||||
|
pub use self::regex::*;
|
Write
Preview
Loading…
Cancel
Save
Reference in new issue