Accept invitation and redirect. Render is broken
This commit is contained in:
parent
3cb74084d9
commit
3ccafecfb9
@ -18,3 +18,8 @@
|
||||
#invite > .styledForm:last-of-type {
|
||||
box-shadow: rgba(0, 0, 0, 0.1) 0 10px 10px;
|
||||
}
|
||||
|
||||
#invite .error {
|
||||
color: var(--danger);
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ use crate::shared::styled_button::StyledButton;
|
||||
use crate::shared::styled_field::StyledField;
|
||||
use crate::shared::styled_form::StyledForm;
|
||||
use crate::shared::styled_input::StyledInput;
|
||||
use crate::shared::{outer_layout, ToNode};
|
||||
use crate::shared::{go_to_board, outer_layout, write_auth_token, ToNode};
|
||||
use crate::validations::is_token;
|
||||
use crate::ws::send_ws_msg;
|
||||
use crate::{FieldId, InvitationPageChange, Msg, PageChanged, WebSocketChanged};
|
||||
@ -27,12 +27,21 @@ pub fn update(msg: Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
|
||||
};
|
||||
|
||||
match msg {
|
||||
Msg::WebSocketChange(WebSocketChanged::WsMsg(WsMsg::InvitationAcceptFailure(_))) => {
|
||||
Msg::WebSocketChange(WebSocketChanged::WsMsg(ws_msg)) => match ws_msg {
|
||||
WsMsg::InvitationAcceptFailure(_) => {
|
||||
page.error = Some("Invalid token".to_string());
|
||||
}
|
||||
WsMsg::InvitationAcceptSuccess(token) => {
|
||||
if let Ok(_) = write_auth_token(Some(token)) {
|
||||
go_to_board(orders);
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
},
|
||||
Msg::StrInputChanged(FieldId::Invite(InviteFieldId::Token), text) => {
|
||||
page.token_touched = true;
|
||||
page.token = text;
|
||||
page.error = None;
|
||||
}
|
||||
Msg::PageChanged(PageChanged::Invitation(InvitationPageChange::SubmitForm)) => {
|
||||
if let Ok(token) = uuid::Uuid::from_str(page.token.as_str()) {
|
||||
@ -97,10 +106,11 @@ fn submit(_page: &Box<InvitePage>) -> Node<Msg> {
|
||||
|
||||
fn token_field(page: &Box<InvitePage>) -> Node<Msg> {
|
||||
let token = StyledInput::build(FieldId::Invite(InviteFieldId::Token))
|
||||
.valid(!page.token_touched || is_token(page.token.as_str()))
|
||||
.valid(!page.token_touched || is_token(page.token.as_str()) && page.error.is_none())
|
||||
.value(page.token.as_str())
|
||||
.build()
|
||||
.into_node();
|
||||
|
||||
StyledField::build()
|
||||
.input(token)
|
||||
.label("Your invite token")
|
||||
|
@ -7,6 +7,8 @@ use jirs_data::{
|
||||
User, UserId, UserRole, UsernameString,
|
||||
};
|
||||
|
||||
use crate::db::tokens::CreateBindToken;
|
||||
use crate::db::users::{FindUser, Register};
|
||||
use crate::db::DbExecutor;
|
||||
use crate::errors::ServiceErrors;
|
||||
|
||||
@ -149,7 +151,7 @@ impl Message for AcceptInvitation {
|
||||
impl Handler<AcceptInvitation> for DbExecutor {
|
||||
type Result = Result<Token, ServiceErrors>;
|
||||
|
||||
fn handle(&mut self, msg: AcceptInvitation, _ctx: &mut Self::Context) -> Self::Result {
|
||||
fn handle(&mut self, msg: AcceptInvitation, ctx: &mut Self::Context) -> Self::Result {
|
||||
use crate::schema::invitations::dsl::*;
|
||||
|
||||
let conn = &self
|
||||
@ -177,21 +179,32 @@ impl Handler<AcceptInvitation> for DbExecutor {
|
||||
.filter(id.eq(invitation.id))
|
||||
.filter(state.eq(InvitationState::Sent));
|
||||
debug!("{}", diesel::debug_query::<Pg, _>(&query).to_string());
|
||||
query
|
||||
.execute(conn)
|
||||
.map_err(|e| ServiceErrors::DatabaseQueryFailed(format!("{}", e)))?;
|
||||
query.execute(conn).map_err(|e| {
|
||||
ServiceErrors::DatabaseQueryFailed(format!("update invitation {} {}", invitation.id, e))
|
||||
})?;
|
||||
|
||||
let user: User = {
|
||||
use crate::schema::users::dsl::*;
|
||||
|
||||
let query = users
|
||||
.filter(name.eq(invitation.name).and(email.eq(invitation.email)))
|
||||
.limit(1);
|
||||
debug!("{}", diesel::debug_query::<Pg, _>(&query));
|
||||
query
|
||||
.first(conn)
|
||||
.map_err(|e| ServiceErrors::DatabaseQueryFailed(format!("{}", e)))?
|
||||
match self.handle(
|
||||
Register {
|
||||
name: invitation.name.clone(),
|
||||
email: invitation.email.clone(),
|
||||
project_id: Some(invitation.project_id),
|
||||
},
|
||||
ctx,
|
||||
) {
|
||||
Ok(_) => (),
|
||||
Err(ServiceErrors::RegisterCollision) => (),
|
||||
Err(e) => return Err(e),
|
||||
};
|
||||
|
||||
let user: User = self.handle(
|
||||
FindUser {
|
||||
name: invitation.name.clone(),
|
||||
email: invitation.email.clone(),
|
||||
},
|
||||
ctx,
|
||||
)?;
|
||||
self.handle(CreateBindToken { user_id: user.id }, ctx)?;
|
||||
|
||||
{
|
||||
use crate::schema::user_projects::dsl::*;
|
||||
|
||||
@ -208,11 +221,12 @@ impl Handler<AcceptInvitation> for DbExecutor {
|
||||
|
||||
let token = {
|
||||
use crate::schema::tokens::dsl::*;
|
||||
let query = tokens.filter(user_id.eq(user.id));
|
||||
|
||||
let query = tokens.filter(user_id.eq(user.id)).order_by(id.desc());
|
||||
debug!("{}", diesel::debug_query::<Pg, _>(&query));
|
||||
query
|
||||
.first(conn)
|
||||
.map_err(|e| ServiceErrors::DatabaseQueryFailed(format!("{}", e)))?
|
||||
query.first(conn).map_err(|e| {
|
||||
ServiceErrors::DatabaseQueryFailed(format!("token for user {} {}", user.id, e))
|
||||
})?
|
||||
};
|
||||
|
||||
Ok(token)
|
||||
|
@ -41,6 +41,45 @@ impl Handler<LoadCurrentProject> for DbExecutor {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct CreateProject {
|
||||
pub name: String,
|
||||
pub url: Option<String>,
|
||||
pub description: Option<String>,
|
||||
pub category: Option<ProjectCategory>,
|
||||
pub time_tracking: Option<TimeTracking>,
|
||||
}
|
||||
|
||||
impl Message for CreateProject {
|
||||
type Result = Result<Project, ServiceErrors>;
|
||||
}
|
||||
|
||||
impl Handler<CreateProject> for DbExecutor {
|
||||
type Result = Result<Project, ServiceErrors>;
|
||||
|
||||
fn handle(&mut self, msg: CreateProject, _ctx: &mut Self::Context) -> Self::Result {
|
||||
use crate::schema::projects::dsl::*;
|
||||
let conn = &self
|
||||
.pool
|
||||
.get()
|
||||
.map_err(|_| ServiceErrors::DatabaseConnectionLost)?;
|
||||
|
||||
let query = diesel::insert_into(projects)
|
||||
.values((
|
||||
name.eq(msg.name),
|
||||
msg.url.map(|v| url.eq(v)),
|
||||
msg.description.map(|v| description.eq(v)),
|
||||
msg.category.map(|v| category.eq(v)),
|
||||
msg.time_tracking.map(|v| time_tracking.eq(v)),
|
||||
))
|
||||
.returning(all_columns);
|
||||
debug!("{}", diesel::debug_query::<Pg, _>(&query));
|
||||
query
|
||||
.get_result::<Project>(conn)
|
||||
.map_err(|e| ServiceErrors::DatabaseQueryFailed(format!("{}", e)))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct UpdateProject {
|
||||
pub project_id: i32,
|
||||
|
@ -3,11 +3,11 @@ use diesel::pg::Pg;
|
||||
use diesel::prelude::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use jirs_data::{Project, User, UserId};
|
||||
use jirs_data::{ProjectId, User, UserId};
|
||||
|
||||
use crate::db::projects::CreateProject;
|
||||
use crate::db::{DbExecutor, DbPooledConn};
|
||||
use crate::errors::ServiceErrors;
|
||||
use crate::models::CreateProjectForm;
|
||||
use crate::schema::users::all_columns;
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
@ -112,6 +112,7 @@ impl Handler<LoadIssueAssignees> for DbExecutor {
|
||||
pub struct Register {
|
||||
pub name: String,
|
||||
pub email: String,
|
||||
pub project_id: Option<ProjectId>,
|
||||
}
|
||||
|
||||
impl Message for Register {
|
||||
@ -121,8 +122,7 @@ impl Message for Register {
|
||||
impl Handler<Register> for DbExecutor {
|
||||
type Result = Result<(), ServiceErrors>;
|
||||
|
||||
fn handle(&mut self, msg: Register, _ctx: &mut Self::Context) -> Self::Result {
|
||||
use crate::schema::projects::dsl::projects;
|
||||
fn handle(&mut self, msg: Register, ctx: &mut Self::Context) -> Self::Result {
|
||||
use crate::schema::users::dsl::*;
|
||||
|
||||
let conn = &self
|
||||
@ -136,17 +136,22 @@ impl Handler<Register> for DbExecutor {
|
||||
return Err(ServiceErrors::RegisterCollision);
|
||||
}
|
||||
|
||||
let form = CreateProjectForm {
|
||||
let current_project_id: ProjectId = match msg.project_id.as_ref().cloned() {
|
||||
Some(current_project_id) => current_project_id,
|
||||
_ => {
|
||||
self.handle(
|
||||
CreateProject {
|
||||
name: "initial".to_string(),
|
||||
url: "".to_string(),
|
||||
description: "".to_string(),
|
||||
category: Default::default(),
|
||||
url: None,
|
||||
description: None,
|
||||
category: None,
|
||||
time_tracking: None,
|
||||
},
|
||||
ctx,
|
||||
)?
|
||||
.id
|
||||
}
|
||||
};
|
||||
let insert_query = diesel::insert_into(projects).values(form);
|
||||
debug!("{}", diesel::debug_query::<Pg, _>(&insert_query));
|
||||
let project: Project = insert_query
|
||||
.get_result(conn)
|
||||
.map_err(|_| ServiceErrors::RegisterCollision)?;
|
||||
|
||||
let user: User = {
|
||||
let insert_user_query =
|
||||
@ -161,7 +166,7 @@ impl Handler<Register> for DbExecutor {
|
||||
use crate::schema::user_projects::dsl::*;
|
||||
let insert_user_project_query = diesel::insert_into(user_projects).values((
|
||||
user_id.eq(user.id),
|
||||
project_id.eq(project.id),
|
||||
project_id.eq(current_project_id),
|
||||
is_current.eq(true),
|
||||
is_default.eq(true),
|
||||
));
|
||||
|
@ -40,6 +40,7 @@ impl WsHandler<Register> for WebSocketActor {
|
||||
let msg = match block_on(self.db.send(DbRegister {
|
||||
name: name.clone(),
|
||||
email: email.clone(),
|
||||
project_id: None,
|
||||
})) {
|
||||
Ok(Ok(_)) => Some(WsMsg::SignUpSuccess),
|
||||
Ok(Err(_)) => Some(WsMsg::SignUpPairTaken),
|
||||
|
Loading…
Reference in New Issue
Block a user