check params using flowy-user entities

This commit is contained in:
appflowy 2021-08-23 23:02:42 +08:00
parent f05f0c43a3
commit d6c761917b
11 changed files with 60 additions and 51 deletions

View File

@ -4,7 +4,7 @@ use crate::{
};
use chrono::{Duration, Local};
use derive_more::{From, Into};
use flowy_net::errors::{Code, ServerError};
use flowy_net::errors::{ErrorCode, ServerError};
use jsonwebtoken::{decode, encode, Algorithm, DecodingKey, EncodingKey, Header, Validation};
use serde::{Deserialize, Serialize};
@ -51,7 +51,7 @@ impl Token {
&EncodingKey::from_secret(jwt_secret().as_ref()),
)
.map(Into::into)
.map_err(|err| ServerError::internal().with_msg(err))
.map_err(|err| ServerError::internal().context(err))
}
pub fn decode_token(token: &Self) -> Result<Claim, ServerError> {
@ -61,6 +61,6 @@ impl Token {
&Validation::new(DEFAULT_ALGORITHM),
)
.map(|data| Ok(data.claims))
.map_err(|err| ServerError::unauthorized().with_msg(err))?
.map_err(|err| ServerError::unauthorized().context(err))?
}
}

View File

@ -1,7 +1,7 @@
use crate::config::MAX_PAYLOAD_SIZE;
use actix_web::web;
use flowy_net::{
errors::{Code, ServerError},
errors::{ErrorCode, ServerError},
response::*,
};
use futures::StreamExt;
@ -23,11 +23,11 @@ pub fn parse_from_bytes<T: Message>(bytes: &[u8]) -> Result<T, ServerError> {
pub async fn poll_payload(mut payload: web::Payload) -> Result<web::BytesMut, ServerError> {
let mut body = web::BytesMut::new();
while let Some(chunk) = payload.next().await {
let chunk = chunk.map_err(|err| ServerError::internal().with_msg(err))?;
let chunk = chunk.map_err(|err| ServerError::internal().context(err))?;
if (body.len() + chunk.len()) > MAX_PAYLOAD_SIZE {
return Err(ServerError {
code: Code::PayloadOverflow,
code: ErrorCode::PayloadOverflow,
msg: "Payload overflow".to_string(),
});
}

View File

@ -6,11 +6,12 @@ use actix_identity::Identity;
use anyhow::Context;
use chrono::Utc;
use flowy_net::{
errors::{Code, ServerError},
errors::{ErrorCode, ServerError},
response::FlowyResponse,
};
use flowy_user::{
entities::{SignInResponse, SignUpResponse},
prelude::parser::{UserEmail, UserPassword},
protobuf::{SignInParams, SignUpParams},
};
use sqlx::{Error, PgPool, Postgres, Transaction};
@ -21,17 +22,23 @@ pub async fn sign_in(
params: SignInParams,
id: Identity,
) -> Result<FlowyResponse, ServerError> {
let email =
UserEmail::parse(params.email).map_err(|e| ServerError::params_invalid().context(e))?;
let password = UserPassword::parse(params.password)
.map_err(|e| ServerError::params_invalid().context(e))?;
let mut transaction = pool
.begin()
.await
.context("Failed to acquire a Postgres connection to sign in")?;
let user = read_user(&mut transaction, &params.email).await?;
let user = read_user(&mut transaction, &email.0).await?;
transaction
.commit()
.await
.context("Failed to commit SQL transaction to sign in.")?;
match verify_password(&params.password, &user.password) {
match verify_password(&password.0, &user.password) {
Ok(true) => {
let token = Token::create_token(&user)?;
let data = SignInResponse {
@ -43,7 +50,7 @@ pub async fn sign_in(
id.remember(data.token.clone());
FlowyResponse::success(data)
},
_ => Err(ServerError::passwordNotMatch()),
_ => Err(ServerError::password_not_match()),
}
}
@ -77,11 +84,11 @@ async fn is_email_exist(
.bind(email)
.fetch_optional(transaction)
.await
.map_err(|err| ServerError::internal().with_msg(err))?;
.map_err(|err| ServerError::internal().context(err))?;
match result {
Some(_) => Err(ServerError {
code: Code::EmailAlreadyExists,
code: ErrorCode::EmailAlreadyExists,
msg: format!("{} already exists", email),
}),
None => Ok(()),
@ -96,7 +103,7 @@ async fn read_user(
.bind(email)
.fetch_one(transaction)
.await
.map_err(|err| ServerError::internal().with_msg(err))?;
.map_err(|err| ServerError::internal().context(err))?;
Ok(user)
}
@ -120,7 +127,7 @@ async fn insert_user(
)
.execute(transaction)
.await
.map_err(|e| ServerError::internal().with_msg(e))?;
.map_err(|e| ServerError::internal().context(e))?;
let data = SignUpResponse {
uid: uuid.to_string(),

View File

@ -1,5 +1,5 @@
use bcrypt::{hash, verify, BcryptError, DEFAULT_COST};
use flowy_net::errors::{Code, ServerError};
use flowy_net::errors::{ErrorCode, ServerError};
use jsonwebtoken::Algorithm;
pub fn uuid() -> String { uuid::Uuid::new_v4().to_string() }
@ -10,14 +10,14 @@ pub fn hash_password(plain: &str) -> Result<String, ServerError> {
.and_then(|c| c.parse().ok())
.unwrap_or(DEFAULT_COST);
hash(plain, hashing_cost).map_err(|e| ServerError::internal().with_msg(e))
hash(plain, hashing_cost).map_err(|e| ServerError::internal().context(e))
}
pub fn verify_password(source: &str, hash: &str) -> Result<bool, ServerError> {
match verify(source, hash) {
Ok(true) => Ok(true),
_ => Err(ServerError {
code: Code::PasswordNotMatch,
code: ErrorCode::PasswordNotMatch,
msg: "Username and password don't match".to_string(),
}),
}

View File

@ -4,4 +4,5 @@ pub const HOST: &'static str = "http://localhost:8000";
lazy_static! {
pub static ref SIGN_UP_URL: String = format!("{}/api/register", HOST);
pub static ref SIGN_IN_URL: String = format!("{}/api/auth", HOST);
}

View File

@ -7,7 +7,7 @@ use crate::response::FlowyResponse;
#[derive(thiserror::Error, Debug, Serialize, Deserialize, Clone)]
pub struct ServerError {
pub code: Code,
pub code: ErrorCode,
pub msg: String,
}
@ -24,13 +24,14 @@ macro_rules! static_error {
}
impl ServerError {
static_error!(internal, Code::InternalError);
static_error!(http, Code::HttpError);
static_error!(payload_none, Code::PayloadUnexpectedNone);
static_error!(unauthorized, Code::Unauthorized);
static_error!(passwordNotMatch, Code::PasswordNotMatch);
static_error!(internal, ErrorCode::InternalError);
static_error!(http, ErrorCode::HttpError);
static_error!(payload_none, ErrorCode::PayloadUnexpectedNone);
static_error!(unauthorized, ErrorCode::Unauthorized);
static_error!(password_not_match, ErrorCode::PasswordNotMatch);
static_error!(params_invalid, ErrorCode::ParamsInvalid);
pub fn with_msg<T: Debug>(mut self, error: T) -> Self {
pub fn context<T: Debug>(mut self, error: T) -> Self {
self.msg = format!("{:?}", error);
self
}
@ -54,7 +55,7 @@ impl std::convert::From<&ServerError> for FlowyResponse {
#[derive(Serialize_repr, Deserialize_repr, PartialEq, Debug, Clone, derive_more::Display)]
#[repr(u16)]
pub enum Code {
pub enum ErrorCode {
#[display(fmt = "Token is invalid")]
InvalidToken = 1,
#[display(fmt = "Unauthorized")]
@ -65,6 +66,8 @@ pub enum Code {
PayloadSerdeFail = 4,
#[display(fmt = "Unexpected empty payload")]
PayloadUnexpectedNone = 5,
#[display(fmt = "Params is invalid")]
ParamsInvalid = 6,
#[display(fmt = "Protobuf serde error")]
ProtobufError = 10,

View File

@ -1,5 +1,5 @@
use crate::{
errors::{Code, ServerError},
errors::{ErrorCode, ServerError},
response::FlowyResponse,
};
use bytes::Bytes;
@ -83,7 +83,7 @@ impl HttpRequestBuilder {
match data {
None => {
let msg = format!("Request: {} receives unexpected empty body", self.url);
Err(ServerError::payload_none().with_msg(msg))
Err(ServerError::payload_none().context(msg))
},
Some(data) => Ok(T2::try_from(data)?),
}
@ -121,7 +121,7 @@ async fn get_response_data(original: Response) -> Result<Bytes, ServerError> {
Some(error) => Err(error),
}
} else {
Err(ServerError::http().with_msg(original))
Err(ServerError::http().context(original))
}
}

View File

@ -1,4 +1,4 @@
use crate::errors::{Code, ServerError};
use crate::errors::{ErrorCode, ServerError};
use bytes::Bytes;
use serde::{Deserialize, Serialize};
use std::{convert::TryInto, error::Error, fmt::Debug};
@ -25,35 +25,35 @@ impl FlowyResponse {
impl std::convert::From<protobuf::ProtobufError> for ServerError {
fn from(err: protobuf::ProtobufError) -> Self {
ServerError {
code: Code::ProtobufError,
code: ErrorCode::ProtobufError,
msg: format!("{}", err),
}
}
}
impl std::convert::From<RecvError> for ServerError {
fn from(error: RecvError) -> Self { ServerError::internal().with_msg(error) }
fn from(error: RecvError) -> Self { ServerError::internal().context(error) }
}
impl std::convert::From<serde_json::Error> for ServerError {
fn from(e: serde_json::Error) -> Self {
let msg = format!("Serial error: {:?}", e);
ServerError {
code: Code::SerdeError,
code: ErrorCode::SerdeError,
msg,
}
}
}
impl std::convert::From<anyhow::Error> for ServerError {
fn from(error: anyhow::Error) -> Self { ServerError::internal().with_msg(error) }
fn from(error: anyhow::Error) -> Self { ServerError::internal().context(error) }
}
impl std::convert::From<reqwest::Error> for ServerError {
fn from(error: reqwest::Error) -> Self {
if error.is_timeout() {
return ServerError {
code: Code::ConnectTimeout,
code: ErrorCode::ConnectTimeout,
msg: format!("{}", error),
};
}
@ -62,22 +62,22 @@ impl std::convert::From<reqwest::Error> for ServerError {
let hyper_error: Option<&hyper::Error> = error.source().unwrap().downcast_ref();
return match hyper_error {
None => ServerError {
code: Code::ConnectRefused,
code: ErrorCode::ConnectRefused,
msg: format!("{:?}", error),
},
Some(hyper_error) => {
let mut code = Code::InternalError;
let mut code = ErrorCode::InternalError;
let msg = format!("{}", error);
if hyper_error.is_closed() {
code = Code::ConnectClose;
code = ErrorCode::ConnectClose;
}
if hyper_error.is_connect() {
code = Code::ConnectRefused;
code = ErrorCode::ConnectRefused;
}
if hyper_error.is_canceled() {
code = Code::ConnectCancel;
code = ErrorCode::ConnectCancel;
}
if hyper_error.is_timeout() {}
@ -89,7 +89,7 @@ impl std::convert::From<reqwest::Error> for ServerError {
let msg = format!("{:?}", error);
ServerError {
code: Code::ProtobufError,
code: ErrorCode::ProtobufError,
msg,
}
}

View File

@ -2,7 +2,7 @@ pub use sign_in::*;
pub use sign_up::*;
pub use user_detail::*;
pub use user_update::*;
mod parser;
pub mod parser;
mod sign_in;
pub mod sign_up;
mod user_detail;

View File

@ -63,6 +63,7 @@ pub enum UserErrCode {
fmt = "Password should contain a minimum of 6 characters with 1 special 1 letter and 1 numeric"
)]
PasswordFormatInvalid = 33,
#[display(fmt = "User name is too long")]
UserNameTooLong = 40,
#[display(fmt = "User name contain forbidden characters")]
@ -83,6 +84,10 @@ pub enum UserErrCode {
NetworkError = 100,
}
impl UserErrCode {
pub fn to_string(&self) -> String { format!("{}", self) }
}
impl std::default::Default for UserErrCode {
fn default() -> Self { UserErrCode::Unknown }
}

View File

@ -4,7 +4,7 @@ use crate::{
};
use flowy_net::{
config::SIGN_UP_URL,
config::*,
future::ResultFuture,
request::{http_post, HttpRequestBuilder},
};
@ -35,15 +35,8 @@ impl UserServer for UserServerImpl {
ResultFuture::new(async move { user_sign_up(params, SIGN_UP_URL.as_ref()).await })
}
fn sign_in(&self, _params: SignInParams) -> ResultFuture<SignInResponse, UserError> {
// let user_id = params.email.clone();
// Ok(UserTable::new(
// user_id,
// "".to_owned(),
// params.email,
// params.password,
// ))
unimplemented!()
fn sign_in(&self, params: SignInParams) -> ResultFuture<SignInResponse, UserError> {
ResultFuture::new(async move { user_sign_in(params, SIGN_IN_URL.as_ref()).await })
}
fn sign_out(&self, _user_id: &str) -> ResultFuture<(), UserError> {