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
-
4README.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
-
89src/routes/users.rs
-
128src/services/user_service.rs
-
4src/utils.rs
-
2src/utils/regex.rs
@ -1,27 +1,130 @@ |
|||
use serde::{Deserialize, Serialize};
|
|||
|
|||
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 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,
|
|||
}
|
|||
|
|||
#[derive(Debug, Clone, Insertable, Deserialize, Validate)]
|
|||
#[derive(Debug, Clone, Insertable, Deserialize)]
|
|||
#[table_name = "users"]
|
|||
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 regexs;
|
|||
pub mod regex;
|
|||
pub use self::auth::*;
|
|||
pub use self::regexs::*;
|
|||
pub use self::regex::*;
|
Write
Preview
Loading…
Cancel
Save
Reference in new issue