mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2025-04-25 07:07:32 -04:00
check params using flowy-user entities
This commit is contained in:
parent
f05f0c43a3
commit
d6c761917b
11 changed files with 60 additions and 51 deletions
|
@ -4,7 +4,7 @@ use crate::{
|
||||||
};
|
};
|
||||||
use chrono::{Duration, Local};
|
use chrono::{Duration, Local};
|
||||||
use derive_more::{From, Into};
|
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 jsonwebtoken::{decode, encode, Algorithm, DecodingKey, EncodingKey, Header, Validation};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
@ -51,7 +51,7 @@ impl Token {
|
||||||
&EncodingKey::from_secret(jwt_secret().as_ref()),
|
&EncodingKey::from_secret(jwt_secret().as_ref()),
|
||||||
)
|
)
|
||||||
.map(Into::into)
|
.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> {
|
pub fn decode_token(token: &Self) -> Result<Claim, ServerError> {
|
||||||
|
@ -61,6 +61,6 @@ impl Token {
|
||||||
&Validation::new(DEFAULT_ALGORITHM),
|
&Validation::new(DEFAULT_ALGORITHM),
|
||||||
)
|
)
|
||||||
.map(|data| Ok(data.claims))
|
.map(|data| Ok(data.claims))
|
||||||
.map_err(|err| ServerError::unauthorized().with_msg(err))?
|
.map_err(|err| ServerError::unauthorized().context(err))?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use crate::config::MAX_PAYLOAD_SIZE;
|
use crate::config::MAX_PAYLOAD_SIZE;
|
||||||
use actix_web::web;
|
use actix_web::web;
|
||||||
use flowy_net::{
|
use flowy_net::{
|
||||||
errors::{Code, ServerError},
|
errors::{ErrorCode, ServerError},
|
||||||
response::*,
|
response::*,
|
||||||
};
|
};
|
||||||
use futures::StreamExt;
|
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> {
|
pub async fn poll_payload(mut payload: web::Payload) -> Result<web::BytesMut, ServerError> {
|
||||||
let mut body = web::BytesMut::new();
|
let mut body = web::BytesMut::new();
|
||||||
while let Some(chunk) = payload.next().await {
|
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 {
|
if (body.len() + chunk.len()) > MAX_PAYLOAD_SIZE {
|
||||||
return Err(ServerError {
|
return Err(ServerError {
|
||||||
code: Code::PayloadOverflow,
|
code: ErrorCode::PayloadOverflow,
|
||||||
msg: "Payload overflow".to_string(),
|
msg: "Payload overflow".to_string(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,11 +6,12 @@ use actix_identity::Identity;
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
use chrono::Utc;
|
use chrono::Utc;
|
||||||
use flowy_net::{
|
use flowy_net::{
|
||||||
errors::{Code, ServerError},
|
errors::{ErrorCode, ServerError},
|
||||||
response::FlowyResponse,
|
response::FlowyResponse,
|
||||||
};
|
};
|
||||||
use flowy_user::{
|
use flowy_user::{
|
||||||
entities::{SignInResponse, SignUpResponse},
|
entities::{SignInResponse, SignUpResponse},
|
||||||
|
prelude::parser::{UserEmail, UserPassword},
|
||||||
protobuf::{SignInParams, SignUpParams},
|
protobuf::{SignInParams, SignUpParams},
|
||||||
};
|
};
|
||||||
use sqlx::{Error, PgPool, Postgres, Transaction};
|
use sqlx::{Error, PgPool, Postgres, Transaction};
|
||||||
|
@ -21,17 +22,23 @@ pub async fn sign_in(
|
||||||
params: SignInParams,
|
params: SignInParams,
|
||||||
id: Identity,
|
id: Identity,
|
||||||
) -> Result<FlowyResponse, ServerError> {
|
) -> 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
|
let mut transaction = pool
|
||||||
.begin()
|
.begin()
|
||||||
.await
|
.await
|
||||||
.context("Failed to acquire a Postgres connection to sign in")?;
|
.context("Failed to acquire a Postgres connection to sign in")?;
|
||||||
let user = read_user(&mut transaction, ¶ms.email).await?;
|
|
||||||
|
let user = read_user(&mut transaction, &email.0).await?;
|
||||||
transaction
|
transaction
|
||||||
.commit()
|
.commit()
|
||||||
.await
|
.await
|
||||||
.context("Failed to commit SQL transaction to sign in.")?;
|
.context("Failed to commit SQL transaction to sign in.")?;
|
||||||
|
|
||||||
match verify_password(¶ms.password, &user.password) {
|
match verify_password(&password.0, &user.password) {
|
||||||
Ok(true) => {
|
Ok(true) => {
|
||||||
let token = Token::create_token(&user)?;
|
let token = Token::create_token(&user)?;
|
||||||
let data = SignInResponse {
|
let data = SignInResponse {
|
||||||
|
@ -43,7 +50,7 @@ pub async fn sign_in(
|
||||||
id.remember(data.token.clone());
|
id.remember(data.token.clone());
|
||||||
FlowyResponse::success(data)
|
FlowyResponse::success(data)
|
||||||
},
|
},
|
||||||
_ => Err(ServerError::passwordNotMatch()),
|
_ => Err(ServerError::password_not_match()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,11 +84,11 @@ async fn is_email_exist(
|
||||||
.bind(email)
|
.bind(email)
|
||||||
.fetch_optional(transaction)
|
.fetch_optional(transaction)
|
||||||
.await
|
.await
|
||||||
.map_err(|err| ServerError::internal().with_msg(err))?;
|
.map_err(|err| ServerError::internal().context(err))?;
|
||||||
|
|
||||||
match result {
|
match result {
|
||||||
Some(_) => Err(ServerError {
|
Some(_) => Err(ServerError {
|
||||||
code: Code::EmailAlreadyExists,
|
code: ErrorCode::EmailAlreadyExists,
|
||||||
msg: format!("{} already exists", email),
|
msg: format!("{} already exists", email),
|
||||||
}),
|
}),
|
||||||
None => Ok(()),
|
None => Ok(()),
|
||||||
|
@ -96,7 +103,7 @@ async fn read_user(
|
||||||
.bind(email)
|
.bind(email)
|
||||||
.fetch_one(transaction)
|
.fetch_one(transaction)
|
||||||
.await
|
.await
|
||||||
.map_err(|err| ServerError::internal().with_msg(err))?;
|
.map_err(|err| ServerError::internal().context(err))?;
|
||||||
|
|
||||||
Ok(user)
|
Ok(user)
|
||||||
}
|
}
|
||||||
|
@ -120,7 +127,7 @@ async fn insert_user(
|
||||||
)
|
)
|
||||||
.execute(transaction)
|
.execute(transaction)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| ServerError::internal().with_msg(e))?;
|
.map_err(|e| ServerError::internal().context(e))?;
|
||||||
|
|
||||||
let data = SignUpResponse {
|
let data = SignUpResponse {
|
||||||
uid: uuid.to_string(),
|
uid: uuid.to_string(),
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use bcrypt::{hash, verify, BcryptError, DEFAULT_COST};
|
use bcrypt::{hash, verify, BcryptError, DEFAULT_COST};
|
||||||
use flowy_net::errors::{Code, ServerError};
|
use flowy_net::errors::{ErrorCode, ServerError};
|
||||||
use jsonwebtoken::Algorithm;
|
use jsonwebtoken::Algorithm;
|
||||||
|
|
||||||
pub fn uuid() -> String { uuid::Uuid::new_v4().to_string() }
|
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())
|
.and_then(|c| c.parse().ok())
|
||||||
.unwrap_or(DEFAULT_COST);
|
.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> {
|
pub fn verify_password(source: &str, hash: &str) -> Result<bool, ServerError> {
|
||||||
match verify(source, hash) {
|
match verify(source, hash) {
|
||||||
Ok(true) => Ok(true),
|
Ok(true) => Ok(true),
|
||||||
_ => Err(ServerError {
|
_ => Err(ServerError {
|
||||||
code: Code::PasswordNotMatch,
|
code: ErrorCode::PasswordNotMatch,
|
||||||
msg: "Username and password don't match".to_string(),
|
msg: "Username and password don't match".to_string(),
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,4 +4,5 @@ pub const HOST: &'static str = "http://localhost:8000";
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
pub static ref SIGN_UP_URL: String = format!("{}/api/register", HOST);
|
pub static ref SIGN_UP_URL: String = format!("{}/api/register", HOST);
|
||||||
|
pub static ref SIGN_IN_URL: String = format!("{}/api/auth", HOST);
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ use crate::response::FlowyResponse;
|
||||||
|
|
||||||
#[derive(thiserror::Error, Debug, Serialize, Deserialize, Clone)]
|
#[derive(thiserror::Error, Debug, Serialize, Deserialize, Clone)]
|
||||||
pub struct ServerError {
|
pub struct ServerError {
|
||||||
pub code: Code,
|
pub code: ErrorCode,
|
||||||
pub msg: String,
|
pub msg: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,13 +24,14 @@ macro_rules! static_error {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ServerError {
|
impl ServerError {
|
||||||
static_error!(internal, Code::InternalError);
|
static_error!(internal, ErrorCode::InternalError);
|
||||||
static_error!(http, Code::HttpError);
|
static_error!(http, ErrorCode::HttpError);
|
||||||
static_error!(payload_none, Code::PayloadUnexpectedNone);
|
static_error!(payload_none, ErrorCode::PayloadUnexpectedNone);
|
||||||
static_error!(unauthorized, Code::Unauthorized);
|
static_error!(unauthorized, ErrorCode::Unauthorized);
|
||||||
static_error!(passwordNotMatch, Code::PasswordNotMatch);
|
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.msg = format!("{:?}", error);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
@ -54,7 +55,7 @@ impl std::convert::From<&ServerError> for FlowyResponse {
|
||||||
|
|
||||||
#[derive(Serialize_repr, Deserialize_repr, PartialEq, Debug, Clone, derive_more::Display)]
|
#[derive(Serialize_repr, Deserialize_repr, PartialEq, Debug, Clone, derive_more::Display)]
|
||||||
#[repr(u16)]
|
#[repr(u16)]
|
||||||
pub enum Code {
|
pub enum ErrorCode {
|
||||||
#[display(fmt = "Token is invalid")]
|
#[display(fmt = "Token is invalid")]
|
||||||
InvalidToken = 1,
|
InvalidToken = 1,
|
||||||
#[display(fmt = "Unauthorized")]
|
#[display(fmt = "Unauthorized")]
|
||||||
|
@ -65,6 +66,8 @@ pub enum Code {
|
||||||
PayloadSerdeFail = 4,
|
PayloadSerdeFail = 4,
|
||||||
#[display(fmt = "Unexpected empty payload")]
|
#[display(fmt = "Unexpected empty payload")]
|
||||||
PayloadUnexpectedNone = 5,
|
PayloadUnexpectedNone = 5,
|
||||||
|
#[display(fmt = "Params is invalid")]
|
||||||
|
ParamsInvalid = 6,
|
||||||
|
|
||||||
#[display(fmt = "Protobuf serde error")]
|
#[display(fmt = "Protobuf serde error")]
|
||||||
ProtobufError = 10,
|
ProtobufError = 10,
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
errors::{Code, ServerError},
|
errors::{ErrorCode, ServerError},
|
||||||
response::FlowyResponse,
|
response::FlowyResponse,
|
||||||
};
|
};
|
||||||
use bytes::Bytes;
|
use bytes::Bytes;
|
||||||
|
@ -83,7 +83,7 @@ impl HttpRequestBuilder {
|
||||||
match data {
|
match data {
|
||||||
None => {
|
None => {
|
||||||
let msg = format!("Request: {} receives unexpected empty body", self.url);
|
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)?),
|
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),
|
Some(error) => Err(error),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Err(ServerError::http().with_msg(original))
|
Err(ServerError::http().context(original))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::errors::{Code, ServerError};
|
use crate::errors::{ErrorCode, ServerError};
|
||||||
use bytes::Bytes;
|
use bytes::Bytes;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::{convert::TryInto, error::Error, fmt::Debug};
|
use std::{convert::TryInto, error::Error, fmt::Debug};
|
||||||
|
@ -25,35 +25,35 @@ impl FlowyResponse {
|
||||||
impl std::convert::From<protobuf::ProtobufError> for ServerError {
|
impl std::convert::From<protobuf::ProtobufError> for ServerError {
|
||||||
fn from(err: protobuf::ProtobufError) -> Self {
|
fn from(err: protobuf::ProtobufError) -> Self {
|
||||||
ServerError {
|
ServerError {
|
||||||
code: Code::ProtobufError,
|
code: ErrorCode::ProtobufError,
|
||||||
msg: format!("{}", err),
|
msg: format!("{}", err),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::convert::From<RecvError> for ServerError {
|
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 {
|
impl std::convert::From<serde_json::Error> for ServerError {
|
||||||
fn from(e: serde_json::Error) -> Self {
|
fn from(e: serde_json::Error) -> Self {
|
||||||
let msg = format!("Serial error: {:?}", e);
|
let msg = format!("Serial error: {:?}", e);
|
||||||
ServerError {
|
ServerError {
|
||||||
code: Code::SerdeError,
|
code: ErrorCode::SerdeError,
|
||||||
msg,
|
msg,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::convert::From<anyhow::Error> for ServerError {
|
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 {
|
impl std::convert::From<reqwest::Error> for ServerError {
|
||||||
fn from(error: reqwest::Error) -> Self {
|
fn from(error: reqwest::Error) -> Self {
|
||||||
if error.is_timeout() {
|
if error.is_timeout() {
|
||||||
return ServerError {
|
return ServerError {
|
||||||
code: Code::ConnectTimeout,
|
code: ErrorCode::ConnectTimeout,
|
||||||
msg: format!("{}", error),
|
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();
|
let hyper_error: Option<&hyper::Error> = error.source().unwrap().downcast_ref();
|
||||||
return match hyper_error {
|
return match hyper_error {
|
||||||
None => ServerError {
|
None => ServerError {
|
||||||
code: Code::ConnectRefused,
|
code: ErrorCode::ConnectRefused,
|
||||||
msg: format!("{:?}", error),
|
msg: format!("{:?}", error),
|
||||||
},
|
},
|
||||||
Some(hyper_error) => {
|
Some(hyper_error) => {
|
||||||
let mut code = Code::InternalError;
|
let mut code = ErrorCode::InternalError;
|
||||||
let msg = format!("{}", error);
|
let msg = format!("{}", error);
|
||||||
if hyper_error.is_closed() {
|
if hyper_error.is_closed() {
|
||||||
code = Code::ConnectClose;
|
code = ErrorCode::ConnectClose;
|
||||||
}
|
}
|
||||||
|
|
||||||
if hyper_error.is_connect() {
|
if hyper_error.is_connect() {
|
||||||
code = Code::ConnectRefused;
|
code = ErrorCode::ConnectRefused;
|
||||||
}
|
}
|
||||||
|
|
||||||
if hyper_error.is_canceled() {
|
if hyper_error.is_canceled() {
|
||||||
code = Code::ConnectCancel;
|
code = ErrorCode::ConnectCancel;
|
||||||
}
|
}
|
||||||
|
|
||||||
if hyper_error.is_timeout() {}
|
if hyper_error.is_timeout() {}
|
||||||
|
@ -89,7 +89,7 @@ impl std::convert::From<reqwest::Error> for ServerError {
|
||||||
|
|
||||||
let msg = format!("{:?}", error);
|
let msg = format!("{:?}", error);
|
||||||
ServerError {
|
ServerError {
|
||||||
code: Code::ProtobufError,
|
code: ErrorCode::ProtobufError,
|
||||||
msg,
|
msg,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ pub use sign_in::*;
|
||||||
pub use sign_up::*;
|
pub use sign_up::*;
|
||||||
pub use user_detail::*;
|
pub use user_detail::*;
|
||||||
pub use user_update::*;
|
pub use user_update::*;
|
||||||
mod parser;
|
pub mod parser;
|
||||||
mod sign_in;
|
mod sign_in;
|
||||||
pub mod sign_up;
|
pub mod sign_up;
|
||||||
mod user_detail;
|
mod user_detail;
|
||||||
|
|
|
@ -63,6 +63,7 @@ pub enum UserErrCode {
|
||||||
fmt = "Password should contain a minimum of 6 characters with 1 special 1 letter and 1 numeric"
|
fmt = "Password should contain a minimum of 6 characters with 1 special 1 letter and 1 numeric"
|
||||||
)]
|
)]
|
||||||
PasswordFormatInvalid = 33,
|
PasswordFormatInvalid = 33,
|
||||||
|
|
||||||
#[display(fmt = "User name is too long")]
|
#[display(fmt = "User name is too long")]
|
||||||
UserNameTooLong = 40,
|
UserNameTooLong = 40,
|
||||||
#[display(fmt = "User name contain forbidden characters")]
|
#[display(fmt = "User name contain forbidden characters")]
|
||||||
|
@ -83,6 +84,10 @@ pub enum UserErrCode {
|
||||||
NetworkError = 100,
|
NetworkError = 100,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl UserErrCode {
|
||||||
|
pub fn to_string(&self) -> String { format!("{}", self) }
|
||||||
|
}
|
||||||
|
|
||||||
impl std::default::Default for UserErrCode {
|
impl std::default::Default for UserErrCode {
|
||||||
fn default() -> Self { UserErrCode::Unknown }
|
fn default() -> Self { UserErrCode::Unknown }
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ use crate::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use flowy_net::{
|
use flowy_net::{
|
||||||
config::SIGN_UP_URL,
|
config::*,
|
||||||
future::ResultFuture,
|
future::ResultFuture,
|
||||||
request::{http_post, HttpRequestBuilder},
|
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 })
|
ResultFuture::new(async move { user_sign_up(params, SIGN_UP_URL.as_ref()).await })
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sign_in(&self, _params: SignInParams) -> ResultFuture<SignInResponse, UserError> {
|
fn sign_in(&self, params: SignInParams) -> ResultFuture<SignInResponse, UserError> {
|
||||||
// let user_id = params.email.clone();
|
ResultFuture::new(async move { user_sign_in(params, SIGN_IN_URL.as_ref()).await })
|
||||||
// Ok(UserTable::new(
|
|
||||||
// user_id,
|
|
||||||
// "".to_owned(),
|
|
||||||
// params.email,
|
|
||||||
// params.password,
|
|
||||||
// ))
|
|
||||||
unimplemented!()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sign_out(&self, _user_id: &str) -> ResultFuture<(), UserError> {
|
fn sign_out(&self, _user_id: &str) -> ResultFuture<(), UserError> {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue