Start register logic
This commit is contained in:
parent
0e2cc62c30
commit
b157d718c7
@ -35,3 +35,13 @@
|
|||||||
display: block;
|
display: block;
|
||||||
line-height: 32px;
|
line-height: 32px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#register .error > p {
|
||||||
|
line-height: 1.4285;
|
||||||
|
color: var(--danger);
|
||||||
|
font-family: var(--font-medium);
|
||||||
|
text-align: center;
|
||||||
|
font-size: 14.5px;
|
||||||
|
border-top: 1px solid var(--danger);
|
||||||
|
margin-top: 15px;
|
||||||
|
}
|
||||||
|
@ -142,6 +142,9 @@ pub enum Msg {
|
|||||||
SignInRequest,
|
SignInRequest,
|
||||||
BindClientRequest,
|
BindClientRequest,
|
||||||
|
|
||||||
|
// sign up
|
||||||
|
SignUpRequest,
|
||||||
|
|
||||||
StyledSelectChanged(FieldId, StyledSelectChange),
|
StyledSelectChanged(FieldId, StyledSelectChange),
|
||||||
|
|
||||||
ChangePage(model::Page),
|
ChangePage(model::Page),
|
||||||
|
@ -236,6 +236,7 @@ pub struct SignUpPage {
|
|||||||
pub username: String,
|
pub username: String,
|
||||||
pub email: String,
|
pub email: String,
|
||||||
pub sign_up_success: bool,
|
pub sign_up_success: bool,
|
||||||
|
pub error: String,
|
||||||
// touched
|
// touched
|
||||||
pub username_touched: bool,
|
pub username_touched: bool,
|
||||||
pub email_touched: bool,
|
pub email_touched: bool,
|
||||||
|
@ -27,6 +27,7 @@ impl StyledLinkBuilder {
|
|||||||
self.children.push(child);
|
self.children.push(child);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_class<S>(mut self, name: S) -> Self
|
pub fn add_class<S>(mut self, name: S) -> Self
|
||||||
where
|
where
|
||||||
S: Into<String>,
|
S: Into<String>,
|
||||||
@ -43,13 +44,12 @@ impl StyledLinkBuilder {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn text<S>(mut self, s: S) -> Self
|
pub fn text<S>(self, s: S) -> Self
|
||||||
where
|
where
|
||||||
S: Into<String>,
|
S: Into<String>,
|
||||||
{
|
{
|
||||||
let text: String = s.into();
|
let text: String = s.into();
|
||||||
self.children.push(span![text]);
|
self.add_child(span![text])
|
||||||
self
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn build(self) -> StyledLink {
|
pub fn build(self) -> StyledLink {
|
||||||
|
@ -121,6 +121,7 @@ pub fn view(model: &model::Model) -> Node<Msg> {
|
|||||||
let register_link = StyledLink::build()
|
let register_link = StyledLink::build()
|
||||||
.text("Register")
|
.text("Register")
|
||||||
.href("/register")
|
.href("/register")
|
||||||
|
.add_class("signUpLink")
|
||||||
.build()
|
.build()
|
||||||
.into_node();
|
.into_node();
|
||||||
let submit_field = StyledField::build()
|
let submit_field = StyledField::build()
|
||||||
|
@ -2,6 +2,7 @@ use seed::{prelude::*, *};
|
|||||||
|
|
||||||
use jirs_data::{SignUpFieldId, WsMsg};
|
use jirs_data::{SignUpFieldId, WsMsg};
|
||||||
|
|
||||||
|
use crate::api::send_ws_msg;
|
||||||
use crate::model::{Page, PageContent, SignUpPage};
|
use crate::model::{Page, PageContent, SignUpPage};
|
||||||
use crate::shared::styled_button::StyledButton;
|
use crate::shared::styled_button::StyledButton;
|
||||||
use crate::shared::styled_field::StyledField;
|
use crate::shared::styled_field::StyledField;
|
||||||
@ -37,9 +38,18 @@ pub fn update(msg: Msg, model: &mut model::Model, _orders: &mut impl Orders<Msg>
|
|||||||
page.email = value;
|
page.email = value;
|
||||||
page.email_touched = true;
|
page.email_touched = true;
|
||||||
}
|
}
|
||||||
|
Msg::SignUpRequest => {
|
||||||
|
send_ws_msg(WsMsg::SignUpRequest(
|
||||||
|
page.email.clone(),
|
||||||
|
page.username.clone(),
|
||||||
|
));
|
||||||
|
}
|
||||||
Msg::WsMsg(WsMsg::SignUpSuccess) => {
|
Msg::WsMsg(WsMsg::SignUpSuccess) => {
|
||||||
page.sign_up_success = true;
|
page.sign_up_success = true;
|
||||||
}
|
}
|
||||||
|
Msg::WsMsg(WsMsg::SignUpPairTaken) => {
|
||||||
|
page.error = "Pair you give is either taken or is not matching".to_string();
|
||||||
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -80,7 +90,7 @@ pub fn view(model: &model::Model) -> Node<Msg> {
|
|||||||
StyledButton::build()
|
StyledButton::build()
|
||||||
.primary()
|
.primary()
|
||||||
.text("Register")
|
.text("Register")
|
||||||
.on_click(mouse_ev(Ev::Click, |_| Msg::SignInRequest))
|
.on_click(mouse_ev(Ev::Click, |_| Msg::SignUpRequest))
|
||||||
}
|
}
|
||||||
.build()
|
.build()
|
||||||
.into_node();
|
.into_node();
|
||||||
@ -88,6 +98,7 @@ pub fn view(model: &model::Model) -> Node<Msg> {
|
|||||||
let sign_in_link = StyledLink::build()
|
let sign_in_link = StyledLink::build()
|
||||||
.text("Sign In")
|
.text("Sign In")
|
||||||
.href("/login")
|
.href("/login")
|
||||||
|
.add_class("signInLink")
|
||||||
.build()
|
.build()
|
||||||
.into_node();
|
.into_node();
|
||||||
|
|
||||||
@ -109,17 +120,24 @@ pub fn view(model: &model::Model) -> Node<Msg> {
|
|||||||
span!["Why I don't see password?"]
|
span!["Why I don't see password?"]
|
||||||
];
|
];
|
||||||
|
|
||||||
|
let error_row = if page.error.is_empty() {
|
||||||
|
empty![]
|
||||||
|
} else {
|
||||||
|
div![class!["error"], p![page.error]]
|
||||||
|
};
|
||||||
|
|
||||||
let sign_up_form = StyledForm::build()
|
let sign_up_form = StyledForm::build()
|
||||||
.heading("Sign In to your account")
|
.heading("Sign In to your account")
|
||||||
.on_submit(ev(Ev::Submit, |ev| {
|
.on_submit(ev(Ev::Submit, |ev| {
|
||||||
ev.stop_propagation();
|
ev.stop_propagation();
|
||||||
ev.prevent_default();
|
ev.prevent_default();
|
||||||
Msg::SignInRequest
|
Msg::SignUpRequest
|
||||||
}))
|
}))
|
||||||
.add_field(username_field)
|
.add_field(username_field)
|
||||||
.add_field(email_field)
|
.add_field(email_field)
|
||||||
.add_field(submit_field)
|
.add_field(submit_field)
|
||||||
.add_field(no_pass_section)
|
.add_field(no_pass_section)
|
||||||
|
.add_field(error_row)
|
||||||
.build()
|
.build()
|
||||||
.into_node();
|
.into_node();
|
||||||
let children = vec![sign_up_form];
|
let children = vec![sign_up_form];
|
||||||
|
@ -530,7 +530,11 @@ pub enum WsMsg {
|
|||||||
BindTokenCheck(Uuid),
|
BindTokenCheck(Uuid),
|
||||||
BindTokenBad,
|
BindTokenBad,
|
||||||
BindTokenOk(Uuid),
|
BindTokenOk(Uuid),
|
||||||
|
|
||||||
|
// Sign up
|
||||||
|
SignUpRequest(EmailString, UsernameString),
|
||||||
SignUpSuccess,
|
SignUpSuccess,
|
||||||
|
SignUpPairTaken,
|
||||||
|
|
||||||
// project page
|
// project page
|
||||||
ProjectRequest,
|
ProjectRequest,
|
||||||
|
@ -99,3 +99,49 @@ impl Handler<LoadIssueAssignees> for DbExecutor {
|
|||||||
Ok(vec)
|
Ok(vec)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
|
pub struct Register {
|
||||||
|
pub name: String,
|
||||||
|
pub email: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Message for Register {
|
||||||
|
type Result = Result<(), ServiceErrors>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Handler<Register> for DbExecutor {
|
||||||
|
type Result = Result<(), ServiceErrors>;
|
||||||
|
|
||||||
|
fn handle(&mut self, msg: Register, _ctx: &mut Self::Context) -> Self::Result {
|
||||||
|
use crate::schema::users::dsl::*;
|
||||||
|
|
||||||
|
let conn = &self
|
||||||
|
.pool
|
||||||
|
.get()
|
||||||
|
.map_err(|_| ServiceErrors::DatabaseConnectionLost)?;
|
||||||
|
|
||||||
|
let query = users
|
||||||
|
.filter(
|
||||||
|
email
|
||||||
|
.eq(msg.email.as_str())
|
||||||
|
.and(name.ne(msg.name.as_str()))
|
||||||
|
.or(email.ne(msg.email.as_str()).and(name.eq(msg.name.as_str())))
|
||||||
|
.or(email.eq(msg.email.as_str()).and(name.eq(msg.name.as_str()))),
|
||||||
|
)
|
||||||
|
.count();
|
||||||
|
|
||||||
|
info!(
|
||||||
|
"{}",
|
||||||
|
diesel::debug_query::<diesel::pg::Pg, _>(&query).to_string()
|
||||||
|
);
|
||||||
|
|
||||||
|
let matching: i64 = query.get_result(conn).unwrap_or(1);
|
||||||
|
|
||||||
|
if matching > 0 {
|
||||||
|
return Err(ServiceErrors::RegisterCollision);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,45 +1,49 @@
|
|||||||
use actix_web::HttpResponse;
|
use actix_web::HttpResponse;
|
||||||
|
|
||||||
use jirs_data::ErrorResponse;
|
use jirs_data::ErrorResponse;
|
||||||
|
|
||||||
const TOKEN_NOT_FOUND: &str = "Token not found";
|
const TOKEN_NOT_FOUND: &str = "Token not found";
|
||||||
const DATABASE_CONNECTION_FAILED: &str = "Database connection failed";
|
const DATABASE_CONNECTION_FAILED: &str = "Database connection failed";
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum ServiceErrors {
|
pub enum ServiceErrors {
|
||||||
Unauthorized,
|
Unauthorized,
|
||||||
DatabaseConnectionLost,
|
DatabaseConnectionLost,
|
||||||
DatabaseQueryFailed(String),
|
DatabaseQueryFailed(String),
|
||||||
RecordNotFound(String),
|
RecordNotFound(String),
|
||||||
}
|
RegisterCollision,
|
||||||
|
}
|
||||||
impl ServiceErrors {
|
|
||||||
pub fn into_http_response(self) -> HttpResponse {
|
impl ServiceErrors {
|
||||||
self.into()
|
pub fn into_http_response(self) -> HttpResponse {
|
||||||
}
|
self.into()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
impl Into<HttpResponse> for ServiceErrors {
|
|
||||||
fn into(self) -> HttpResponse {
|
impl Into<HttpResponse> for ServiceErrors {
|
||||||
match self {
|
fn into(self) -> HttpResponse {
|
||||||
ServiceErrors::Unauthorized => HttpResponse::Unauthorized().json(ErrorResponse {
|
match self {
|
||||||
errors: vec![TOKEN_NOT_FOUND.to_owned()],
|
ServiceErrors::Unauthorized => HttpResponse::Unauthorized().json(ErrorResponse {
|
||||||
}),
|
errors: vec![TOKEN_NOT_FOUND.to_owned()],
|
||||||
ServiceErrors::DatabaseConnectionLost => {
|
}),
|
||||||
HttpResponse::InternalServerError().json(ErrorResponse {
|
ServiceErrors::DatabaseConnectionLost => {
|
||||||
errors: vec![DATABASE_CONNECTION_FAILED.to_owned()],
|
HttpResponse::InternalServerError().json(ErrorResponse {
|
||||||
})
|
errors: vec![DATABASE_CONNECTION_FAILED.to_owned()],
|
||||||
}
|
})
|
||||||
ServiceErrors::DatabaseQueryFailed(error) => {
|
}
|
||||||
HttpResponse::BadRequest().json(ErrorResponse {
|
ServiceErrors::DatabaseQueryFailed(error) => {
|
||||||
errors: vec![error],
|
HttpResponse::BadRequest().json(ErrorResponse {
|
||||||
})
|
errors: vec![error],
|
||||||
}
|
})
|
||||||
ServiceErrors::RecordNotFound(resource_name) => {
|
}
|
||||||
HttpResponse::BadRequest().json(ErrorResponse {
|
ServiceErrors::RecordNotFound(resource_name) => {
|
||||||
errors: vec![format!("Resource not found {}", resource_name)],
|
HttpResponse::BadRequest().json(ErrorResponse {
|
||||||
})
|
errors: vec![format!("Resource not found {}", resource_name)],
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
}
|
ServiceErrors::RegisterCollision => HttpResponse::Unauthorized().json(ErrorResponse {
|
||||||
}
|
errors: vec!["Register collision".to_string()],
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -90,6 +90,11 @@ impl WebSocketActor {
|
|||||||
block_on(auth::authenticate(&self.db, &self.mail, name, email))?
|
block_on(auth::authenticate(&self.db, &self.mail, name, email))?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// register
|
||||||
|
WsMsg::SignUpRequest(email, username) => {
|
||||||
|
block_on(users::register(&self.db, &self.mail, username, email))?
|
||||||
|
}
|
||||||
|
|
||||||
// users
|
// users
|
||||||
WsMsg::ProjectUsersRequest => {
|
WsMsg::ProjectUsersRequest => {
|
||||||
block_on(users::load_project_users(&self.db, &self.current_user))?
|
block_on(users::load_project_users(&self.db, &self.current_user))?
|
||||||
|
@ -3,8 +3,9 @@ use actix_web::web::Data;
|
|||||||
|
|
||||||
use jirs_data::WsMsg;
|
use jirs_data::WsMsg;
|
||||||
|
|
||||||
use crate::db::users::LoadProjectUsers;
|
use crate::db::users::{LoadProjectUsers, Register};
|
||||||
use crate::db::DbExecutor;
|
use crate::db::DbExecutor;
|
||||||
|
use crate::mail::MailExecutor;
|
||||||
use crate::ws::{current_user, WsResult};
|
use crate::ws::{current_user, WsResult};
|
||||||
|
|
||||||
pub async fn load_project_users(
|
pub async fn load_project_users(
|
||||||
@ -20,3 +21,17 @@ pub async fn load_project_users(
|
|||||||
};
|
};
|
||||||
Ok(m)
|
Ok(m)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn register(
|
||||||
|
db: &Data<Addr<DbExecutor>>,
|
||||||
|
_mail: &Data<Addr<MailExecutor>>,
|
||||||
|
name: String,
|
||||||
|
email: String,
|
||||||
|
) -> WsResult {
|
||||||
|
let msg = match db.send(Register { name, email }).await {
|
||||||
|
Ok(Ok(_)) => Some(WsMsg::SignUpSuccess),
|
||||||
|
Ok(Err(_)) => Some(WsMsg::SignUpPairTaken),
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
Ok(msg)
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user