Fix roles
This commit is contained in:
parent
372b9d9b8d
commit
e618a4f23c
@ -103,3 +103,7 @@
|
|||||||
.modal > .clickableOverlay > .styledModal.confirmModal > .actions > .styledButton {
|
.modal > .clickableOverlay > .styledModal.confirmModal > .actions > .styledButton {
|
||||||
margin-right: 10px;
|
margin-right: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.modal > .clickableOverlay > .styledModal.debugModal {
|
||||||
|
padding-left: 15px;
|
||||||
|
}
|
||||||
|
@ -174,8 +174,8 @@ fn update(msg: Msg, model: &mut model::Model, orders: &mut impl Orders<Msg>) {
|
|||||||
},
|
},
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
crate::modal::update(&msg, model, orders);
|
|
||||||
crate::shared::aside::update(&msg, model, orders);
|
crate::shared::aside::update(&msg, model, orders);
|
||||||
|
crate::modal::update(&msg, model, orders);
|
||||||
match model.page {
|
match model.page {
|
||||||
Page::Project | Page::AddIssue | Page::EditIssue(..) => project::update(msg, model, orders),
|
Page::Project | Page::AddIssue | Page::EditIssue(..) => project::update(msg, model, orders),
|
||||||
Page::ProjectSettings => project_settings::update(msg, model, orders),
|
Page::ProjectSettings => project_settings::update(msg, model, orders),
|
||||||
|
18
jirs-client/src/modal/debug_modal.rs
Normal file
18
jirs-client/src/modal/debug_modal.rs
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
use seed::{prelude::*, *};
|
||||||
|
|
||||||
|
use crate::model::Model;
|
||||||
|
use crate::shared::styled_modal::StyledModal;
|
||||||
|
use crate::shared::ToNode;
|
||||||
|
use crate::Msg;
|
||||||
|
|
||||||
|
pub fn view(model: &Model) -> Node<Msg> {
|
||||||
|
let text = format!("{:#?}", model);
|
||||||
|
let code = pre![text];
|
||||||
|
StyledModal::build()
|
||||||
|
.width(1200)
|
||||||
|
.add_class("debugModal")
|
||||||
|
.center()
|
||||||
|
.children(vec![code])
|
||||||
|
.build()
|
||||||
|
.into_node()
|
||||||
|
}
|
@ -11,6 +11,8 @@ use crate::{model, FieldChange, FieldId, Msg, WebSocketChanged};
|
|||||||
|
|
||||||
mod add_issue;
|
mod add_issue;
|
||||||
mod confirm_delete_issue;
|
mod confirm_delete_issue;
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
mod debug_modal;
|
||||||
mod delete_issue_status;
|
mod delete_issue_status;
|
||||||
mod issue_details;
|
mod issue_details;
|
||||||
pub mod time_tracking;
|
pub mod time_tracking;
|
||||||
@ -55,6 +57,11 @@ pub fn update(msg: &Msg, model: &mut model::Model, orders: &mut impl Orders<Msg>
|
|||||||
model.modals.push(ModalType::AddIssue(Box::new(modal)));
|
model.modals.push(ModalType::AddIssue(Box::new(modal)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
Msg::GlobalKeyDown { key, .. } if key.eq("#") => {
|
||||||
|
model.modals.push(ModalType::DebugModal);
|
||||||
|
}
|
||||||
|
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
add_issue::update(msg, model, orders);
|
add_issue::update(msg, model, orders);
|
||||||
@ -96,6 +103,8 @@ pub fn view(model: &model::Model) -> Node<Msg> {
|
|||||||
ModalType::DeleteIssueStatusModal(delete_issue_modal) => {
|
ModalType::DeleteIssueStatusModal(delete_issue_modal) => {
|
||||||
delete_issue_status::view(model, delete_issue_modal.delete_id)
|
delete_issue_status::view(model, delete_issue_modal.delete_id)
|
||||||
}
|
}
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
ModalType::DebugModal => debug_modal::view(model),
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
section![id!["modals"], modals]
|
section![id!["modals"], modals]
|
||||||
|
@ -23,6 +23,8 @@ pub enum ModalType {
|
|||||||
DeleteCommentConfirm(CommentId),
|
DeleteCommentConfirm(CommentId),
|
||||||
TimeTracking(IssueId),
|
TimeTracking(IssueId),
|
||||||
DeleteIssueStatusModal(Box<DeleteIssueStatusModal>),
|
DeleteIssueStatusModal(Box<DeleteIssueStatusModal>),
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
DebugModal,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialOrd, PartialEq)]
|
#[derive(Clone, Debug, PartialOrd, PartialEq)]
|
||||||
|
@ -63,9 +63,9 @@ impl StyledModalBuilder {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
// pub fn center(mut self) -> Self {
|
pub fn center(self) -> Self {
|
||||||
// self.variant(Variant::Center)
|
self.variant(Variant::Center)
|
||||||
// }
|
}
|
||||||
|
|
||||||
pub fn width(mut self, width: usize) -> Self {
|
pub fn width(mut self, width: usize) -> Self {
|
||||||
self.width = Some(width);
|
self.width = Some(width);
|
||||||
|
5
jirs-client/src/users/mod.rs
Normal file
5
jirs-client/src/users/mod.rs
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
pub use update::*;
|
||||||
|
pub use view::*;
|
||||||
|
|
||||||
|
mod update;
|
||||||
|
mod view;
|
134
jirs-client/src/users/update.rs
Normal file
134
jirs-client/src/users/update.rs
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
use seed::prelude::Orders;
|
||||||
|
|
||||||
|
use jirs_data::{InvitationState, UserRole, UsersFieldId, WsMsg};
|
||||||
|
|
||||||
|
use crate::model::{InvitationFormState, Model, Page, PageContent, UsersPage};
|
||||||
|
use crate::shared::styled_select::StyledSelectChange;
|
||||||
|
use crate::ws::{enqueue_ws_msg, send_ws_msg};
|
||||||
|
use crate::{FieldId, Msg, PageChanged, UsersPageChange, WebSocketChanged};
|
||||||
|
|
||||||
|
pub fn update(msg: Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
|
||||||
|
if let Msg::ChangePage(Page::Users) = msg {
|
||||||
|
build_page_content(model);
|
||||||
|
// return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let page = match &mut model.page_content {
|
||||||
|
PageContent::Users(page) => page,
|
||||||
|
_ => return,
|
||||||
|
};
|
||||||
|
|
||||||
|
page.user_role_state.update(&msg, orders);
|
||||||
|
|
||||||
|
match msg {
|
||||||
|
Msg::ChangePage(Page::Users) if model.user.is_some() => {
|
||||||
|
init_load(model, orders);
|
||||||
|
}
|
||||||
|
Msg::WebSocketChange(change) => match change {
|
||||||
|
WebSocketChanged::WsMsg(WsMsg::AuthorizeLoaded(Ok(_))) if model.user.is_some() => {
|
||||||
|
init_load(model, orders);
|
||||||
|
}
|
||||||
|
WebSocketChanged::WsMsg(WsMsg::InvitedUsersLoaded(users)) => {
|
||||||
|
page.invited_users = users;
|
||||||
|
}
|
||||||
|
WebSocketChanged::WsMsg(WsMsg::InvitationListLoaded(invitations)) => {
|
||||||
|
page.invitations = invitations;
|
||||||
|
}
|
||||||
|
WebSocketChanged::WsMsg(WsMsg::InvitationRevokeSuccess(id)) => {
|
||||||
|
let mut old = vec![];
|
||||||
|
std::mem::swap(&mut page.invitations, &mut old);
|
||||||
|
for mut invitation in old {
|
||||||
|
if id == invitation.id {
|
||||||
|
invitation.state = InvitationState::Revoked;
|
||||||
|
}
|
||||||
|
page.invitations.push(invitation);
|
||||||
|
}
|
||||||
|
send_ws_msg(WsMsg::InvitationListRequest, model.ws.as_ref(), orders);
|
||||||
|
}
|
||||||
|
WebSocketChanged::WsMsg(WsMsg::InvitedUserRemoveSuccess(email)) => {
|
||||||
|
let mut old = vec![];
|
||||||
|
std::mem::swap(&mut page.invited_users, &mut old);
|
||||||
|
for user in old {
|
||||||
|
if user.email != email {
|
||||||
|
page.invited_users.push(user);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
WebSocketChanged::WsMsg(WsMsg::InvitationSendSuccess) => {
|
||||||
|
send_ws_msg(WsMsg::InvitationListRequest, model.ws.as_ref(), orders);
|
||||||
|
page.form_state = InvitationFormState::Succeed;
|
||||||
|
}
|
||||||
|
WebSocketChanged::WsMsg(WsMsg::InvitationSendFailure) => {
|
||||||
|
page.form_state = InvitationFormState::Failed;
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
},
|
||||||
|
Msg::PageChanged(PageChanged::Users(UsersPageChange::ResetForm)) => {
|
||||||
|
page.name.clear();
|
||||||
|
page.name_touched = false;
|
||||||
|
page.email.clear();
|
||||||
|
page.email_touched = false;
|
||||||
|
page.user_role = UserRole::User;
|
||||||
|
page.user_role_state.reset();
|
||||||
|
page.form_state = InvitationFormState::Initial;
|
||||||
|
}
|
||||||
|
Msg::StyledSelectChanged(
|
||||||
|
FieldId::Users(UsersFieldId::UserRole),
|
||||||
|
StyledSelectChange::Changed(role),
|
||||||
|
) => {
|
||||||
|
page.user_role = role.into();
|
||||||
|
}
|
||||||
|
Msg::StrInputChanged(FieldId::Users(UsersFieldId::Username), name) => {
|
||||||
|
page.name = name;
|
||||||
|
page.name_touched = true;
|
||||||
|
}
|
||||||
|
Msg::StrInputChanged(FieldId::Users(UsersFieldId::Email), email) => {
|
||||||
|
page.email = email;
|
||||||
|
page.email_touched = true;
|
||||||
|
}
|
||||||
|
Msg::InviteRequest => {
|
||||||
|
let role: UserRole = match page.user_role_state.values.first() {
|
||||||
|
Some(i) => (*i).into(),
|
||||||
|
_ => return,
|
||||||
|
};
|
||||||
|
|
||||||
|
page.form_state = InvitationFormState::Sent;
|
||||||
|
send_ws_msg(
|
||||||
|
WsMsg::InvitationSendRequest {
|
||||||
|
name: page.name.clone(),
|
||||||
|
email: page.email.clone(),
|
||||||
|
role,
|
||||||
|
},
|
||||||
|
model.ws.as_ref(),
|
||||||
|
orders,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Msg::InviteRevokeRequest(invitation_id) => {
|
||||||
|
send_ws_msg(
|
||||||
|
WsMsg::InvitationRevokeRequest(invitation_id),
|
||||||
|
model.ws.as_ref(),
|
||||||
|
orders,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Msg::InvitedUserRemove(email) => {
|
||||||
|
send_ws_msg(
|
||||||
|
WsMsg::InvitedUserRemoveRequest(email),
|
||||||
|
model.ws.as_ref(),
|
||||||
|
orders,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build_page_content(model: &mut Model) {
|
||||||
|
model.page_content = PageContent::Users(Box::new(UsersPage::default()));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn init_load(model: &mut Model, orders: &mut impl Orders<Msg>) {
|
||||||
|
enqueue_ws_msg(
|
||||||
|
vec![WsMsg::InvitationListRequest, WsMsg::InvitedUsersRequest],
|
||||||
|
model.ws.as_ref(),
|
||||||
|
orders,
|
||||||
|
);
|
||||||
|
}
|
@ -1,133 +1,16 @@
|
|||||||
use seed::{prelude::*, *};
|
use seed::{prelude::*, *};
|
||||||
|
|
||||||
use jirs_data::{InvitationState, ToVec, UserRole, UsersFieldId, WsMsg};
|
use jirs_data::{InvitationState, ToVec, UserRole, UsersFieldId};
|
||||||
|
|
||||||
use crate::model::*;
|
use crate::model::{InvitationFormState, Model, PageContent};
|
||||||
use crate::shared::styled_button::StyledButton;
|
use crate::shared::styled_button::StyledButton;
|
||||||
use crate::shared::styled_field::StyledField;
|
use crate::shared::styled_field::StyledField;
|
||||||
use crate::shared::styled_form::StyledForm;
|
use crate::shared::styled_form::StyledForm;
|
||||||
use crate::shared::styled_input::StyledInput;
|
use crate::shared::styled_input::StyledInput;
|
||||||
use crate::shared::styled_select::*;
|
use crate::shared::styled_select::StyledSelect;
|
||||||
use crate::shared::{inner_layout, ToChild, ToNode};
|
use crate::shared::{inner_layout, ToChild, ToNode};
|
||||||
use crate::validations::is_email;
|
use crate::validations::is_email;
|
||||||
use crate::ws::{enqueue_ws_msg, send_ws_msg};
|
use crate::{FieldId, Msg, PageChanged, UsersPageChange};
|
||||||
use crate::{FieldId, Msg, PageChanged, UsersPageChange, WebSocketChanged};
|
|
||||||
|
|
||||||
pub fn update(msg: Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
|
|
||||||
if let Msg::ChangePage(Page::Users) = msg {
|
|
||||||
model.page_content = PageContent::Users(Box::new(UsersPage::default()));
|
|
||||||
// return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let page = match &mut model.page_content {
|
|
||||||
PageContent::Users(page) => page,
|
|
||||||
_ => return,
|
|
||||||
};
|
|
||||||
|
|
||||||
page.user_role_state.update(&msg, orders);
|
|
||||||
|
|
||||||
match msg {
|
|
||||||
Msg::ChangePage(Page::Users) if model.user.is_some() => {
|
|
||||||
enqueue_ws_msg(
|
|
||||||
vec![WsMsg::InvitationListRequest, WsMsg::InvitedUsersRequest],
|
|
||||||
model.ws.as_ref(),
|
|
||||||
orders,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
Msg::WebSocketChange(change) => match change {
|
|
||||||
WebSocketChanged::WsMsg(WsMsg::AuthorizeLoaded(Ok(_))) if model.user.is_some() => {
|
|
||||||
enqueue_ws_msg(
|
|
||||||
vec![WsMsg::InvitationListRequest, WsMsg::InvitedUsersRequest],
|
|
||||||
model.ws.as_ref(),
|
|
||||||
orders,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
WebSocketChanged::WsMsg(WsMsg::InvitedUsersLoaded(users)) => {
|
|
||||||
page.invited_users = users;
|
|
||||||
}
|
|
||||||
WebSocketChanged::WsMsg(WsMsg::InvitationListLoaded(invitations)) => {
|
|
||||||
page.invitations = invitations;
|
|
||||||
}
|
|
||||||
WebSocketChanged::WsMsg(WsMsg::InvitationRevokeSuccess(id)) => {
|
|
||||||
let mut old = vec![];
|
|
||||||
std::mem::swap(&mut page.invitations, &mut old);
|
|
||||||
for mut invitation in old {
|
|
||||||
if id == invitation.id {
|
|
||||||
invitation.state = InvitationState::Revoked;
|
|
||||||
}
|
|
||||||
page.invitations.push(invitation);
|
|
||||||
}
|
|
||||||
send_ws_msg(WsMsg::InvitationListRequest, model.ws.as_ref(), orders);
|
|
||||||
}
|
|
||||||
WebSocketChanged::WsMsg(WsMsg::InvitedUserRemoveSuccess(email)) => {
|
|
||||||
let mut old = vec![];
|
|
||||||
std::mem::swap(&mut page.invited_users, &mut old);
|
|
||||||
for user in old {
|
|
||||||
if user.email != email {
|
|
||||||
page.invited_users.push(user);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
WebSocketChanged::WsMsg(WsMsg::InvitationSendSuccess) => {
|
|
||||||
send_ws_msg(WsMsg::InvitationListRequest, model.ws.as_ref(), orders);
|
|
||||||
page.form_state = InvitationFormState::Succeed;
|
|
||||||
}
|
|
||||||
WebSocketChanged::WsMsg(WsMsg::InvitationSendFailure) => {
|
|
||||||
page.form_state = InvitationFormState::Failed;
|
|
||||||
}
|
|
||||||
_ => (),
|
|
||||||
},
|
|
||||||
Msg::PageChanged(PageChanged::Users(UsersPageChange::ResetForm)) => {
|
|
||||||
page.name.clear();
|
|
||||||
page.name_touched = false;
|
|
||||||
page.email.clear();
|
|
||||||
page.email_touched = false;
|
|
||||||
page.user_role = UserRole::User;
|
|
||||||
page.user_role_state.reset();
|
|
||||||
page.form_state = InvitationFormState::Initial;
|
|
||||||
}
|
|
||||||
Msg::StyledSelectChanged(
|
|
||||||
FieldId::Users(UsersFieldId::UserRole),
|
|
||||||
StyledSelectChange::Changed(role),
|
|
||||||
) => {
|
|
||||||
page.user_role = role.into();
|
|
||||||
}
|
|
||||||
Msg::StrInputChanged(FieldId::Users(UsersFieldId::Username), name) => {
|
|
||||||
page.name = name;
|
|
||||||
page.name_touched = true;
|
|
||||||
}
|
|
||||||
Msg::StrInputChanged(FieldId::Users(UsersFieldId::Email), email) => {
|
|
||||||
page.email = email;
|
|
||||||
page.email_touched = true;
|
|
||||||
}
|
|
||||||
Msg::InviteRequest => {
|
|
||||||
page.form_state = InvitationFormState::Sent;
|
|
||||||
send_ws_msg(
|
|
||||||
WsMsg::InvitationSendRequest {
|
|
||||||
name: page.name.clone(),
|
|
||||||
email: page.email.clone(),
|
|
||||||
},
|
|
||||||
model.ws.as_ref(),
|
|
||||||
orders,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
Msg::InviteRevokeRequest(invitation_id) => {
|
|
||||||
send_ws_msg(
|
|
||||||
WsMsg::InvitationRevokeRequest(invitation_id),
|
|
||||||
model.ws.as_ref(),
|
|
||||||
orders,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
Msg::InvitedUserRemove(email) => {
|
|
||||||
send_ws_msg(
|
|
||||||
WsMsg::InvitedUserRemoveRequest(email),
|
|
||||||
model.ws.as_ref(),
|
|
||||||
orders,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
_ => (),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn view(model: &Model) -> Node<Msg> {
|
pub fn view(model: &Model) -> Node<Msg> {
|
||||||
if model.user.is_none() {
|
if model.user.is_none() {
|
||||||
@ -231,12 +114,18 @@ pub fn view(model: &Model) -> Node<Msg> {
|
|||||||
.on_click(mouse_ev(Ev::Click, move |_| Msg::InvitedUserRemove(email)))
|
.on_click(mouse_ev(Ev::Click, move |_| Msg::InvitedUserRemove(email)))
|
||||||
.build()
|
.build()
|
||||||
.into_node();
|
.into_node();
|
||||||
|
let role = page
|
||||||
|
.invitations
|
||||||
|
.iter()
|
||||||
|
.find(|iv| iv.email.eq(user.email.as_str()) && iv.name.eq(user.name.as_str()))
|
||||||
|
.map(|iv| iv.role)
|
||||||
|
.unwrap_or_default();
|
||||||
|
|
||||||
// span![format!("{}", user.user_role)],
|
|
||||||
li![
|
li![
|
||||||
class!["user"],
|
class!["user"],
|
||||||
span![user.name.as_str()],
|
span![user.name.as_str()],
|
||||||
span![user.email.as_str()],
|
span![user.email.as_str()],
|
||||||
|
span![format!("{}", role)],
|
||||||
remove,
|
remove,
|
||||||
]
|
]
|
||||||
})
|
})
|
@ -79,8 +79,10 @@ pub fn update(msg: &WsMsg, model: &mut Model, orders: &mut impl Orders<Msg>) {
|
|||||||
// auth
|
// auth
|
||||||
WsMsg::AuthorizeLoaded(Ok(user)) => {
|
WsMsg::AuthorizeLoaded(Ok(user)) => {
|
||||||
model.user = Some(user.clone());
|
model.user = Some(user.clone());
|
||||||
|
if is_non_logged_area() {
|
||||||
go_to_board(orders);
|
go_to_board(orders);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
WsMsg::AuthorizeExpired => {
|
WsMsg::AuthorizeExpired => {
|
||||||
if let Ok(msg) = write_auth_token(None) {
|
if let Ok(msg) = write_auth_token(None) {
|
||||||
orders.skip().send_msg(msg);
|
orders.skip().send_msg(msg);
|
||||||
@ -217,3 +219,11 @@ pub fn update(msg: &WsMsg, model: &mut Model, orders: &mut impl Orders<Msg>) {
|
|||||||
};
|
};
|
||||||
orders.render();
|
orders.render();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_non_logged_area() -> bool {
|
||||||
|
let pathname = seed::document().location().unwrap().pathname().unwrap();
|
||||||
|
match pathname.as_str() {
|
||||||
|
"/login" | "/register" | "/invite" => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -449,6 +449,7 @@ pub struct Invitation {
|
|||||||
pub created_at: NaiveDateTime,
|
pub created_at: NaiveDateTime,
|
||||||
pub updated_at: NaiveDateTime,
|
pub updated_at: NaiveDateTime,
|
||||||
pub bind_token: Uuid,
|
pub bind_token: Uuid,
|
||||||
|
pub role: UserRole,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "backend", derive(Queryable))]
|
#[cfg_attr(feature = "backend", derive(Queryable))]
|
||||||
@ -696,6 +697,7 @@ pub enum WsMsg {
|
|||||||
InvitationSendRequest {
|
InvitationSendRequest {
|
||||||
name: UsernameString,
|
name: UsernameString,
|
||||||
email: EmailString,
|
email: EmailString,
|
||||||
|
role: UserRole,
|
||||||
},
|
},
|
||||||
InvitationSendSuccess,
|
InvitationSendSuccess,
|
||||||
InvitationSendFailure,
|
InvitationSendFailure,
|
||||||
|
@ -0,0 +1 @@
|
|||||||
|
ALTER TABLE invitations DROP COLUMN role;
|
@ -0,0 +1 @@
|
|||||||
|
ALTER TABLE invitations ADD COLUMN role "UserRoleType" NOT NULL DEFAULT 'user';
|
@ -3,12 +3,12 @@ use diesel::pg::Pg;
|
|||||||
use diesel::prelude::*;
|
use diesel::prelude::*;
|
||||||
|
|
||||||
use jirs_data::{
|
use jirs_data::{
|
||||||
EmailString, Invitation, InvitationId, InvitationState, ProjectId, User, UserId, UsernameString,
|
EmailString, Invitation, InvitationId, InvitationState, ProjectId, User, UserId, UserRole,
|
||||||
|
UsernameString,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::db::DbExecutor;
|
use crate::db::DbExecutor;
|
||||||
use crate::errors::ServiceErrors;
|
use crate::errors::ServiceErrors;
|
||||||
use crate::models::InvitationForm;
|
|
||||||
|
|
||||||
pub struct ListInvitation {
|
pub struct ListInvitation {
|
||||||
pub user_id: UserId,
|
pub user_id: UserId,
|
||||||
@ -46,6 +46,7 @@ pub struct CreateInvitation {
|
|||||||
pub project_id: ProjectId,
|
pub project_id: ProjectId,
|
||||||
pub email: EmailString,
|
pub email: EmailString,
|
||||||
pub name: UsernameString,
|
pub name: UsernameString,
|
||||||
|
pub role: UserRole,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Message for CreateInvitation {
|
impl Message for CreateInvitation {
|
||||||
@ -63,14 +64,14 @@ impl Handler<CreateInvitation> for DbExecutor {
|
|||||||
.get()
|
.get()
|
||||||
.map_err(|e| ServiceErrors::DatabaseQueryFailed(format!("{}", e)))?;
|
.map_err(|e| ServiceErrors::DatabaseQueryFailed(format!("{}", e)))?;
|
||||||
|
|
||||||
let form = InvitationForm {
|
let query = diesel::insert_into(invitations).values((
|
||||||
name: msg.name,
|
name.eq(msg.name),
|
||||||
email: msg.email,
|
email.eq(msg.email),
|
||||||
state: InvitationState::Sent,
|
state.eq(InvitationState::Sent),
|
||||||
project_id: msg.project_id,
|
project_id.eq(msg.project_id),
|
||||||
invited_by_id: msg.user_id,
|
invited_by_id.eq(msg.user_id),
|
||||||
};
|
role.eq(msg.role),
|
||||||
let query = diesel::insert_into(invitations).values(form);
|
));
|
||||||
debug!("{}", diesel::debug_query::<Pg, _>(&query).to_string());
|
debug!("{}", diesel::debug_query::<Pg, _>(&query).to_string());
|
||||||
query
|
query
|
||||||
.get_result(conn)
|
.get_result(conn)
|
||||||
@ -183,18 +184,22 @@ impl Handler<AcceptInvitation> for DbExecutor {
|
|||||||
let user: User = {
|
let user: User = {
|
||||||
use crate::schema::users::dsl::*;
|
use crate::schema::users::dsl::*;
|
||||||
|
|
||||||
let query = diesel::insert_into(users)
|
let query = users
|
||||||
.values((name.eq(invitation.name), email.eq(invitation.email)));
|
.filter(name.eq(invitation.name).and(email.eq(invitation.email)))
|
||||||
|
.limit(1);
|
||||||
debug!("{}", diesel::debug_query::<Pg, _>(&query));
|
debug!("{}", diesel::debug_query::<Pg, _>(&query));
|
||||||
query
|
query
|
||||||
.get_result(conn)
|
.first(conn)
|
||||||
.map_err(|e| ServiceErrors::DatabaseQueryFailed(format!("{}", e)))?
|
.map_err(|e| ServiceErrors::DatabaseQueryFailed(format!("{}", e)))?
|
||||||
};
|
};
|
||||||
{
|
{
|
||||||
use crate::schema::user_projects::dsl::*;
|
use crate::schema::user_projects::dsl::*;
|
||||||
|
|
||||||
let query = diesel::insert_into(user_projects)
|
let query = diesel::insert_into(user_projects).values((
|
||||||
.values((user_id.eq(user.id), project_id.eq(invitation.project_id)));
|
user_id.eq(user.id),
|
||||||
|
project_id.eq(invitation.project_id),
|
||||||
|
role.eq(invitation.role),
|
||||||
|
));
|
||||||
debug!("{}", diesel::debug_query::<Pg, _>(&query));
|
debug!("{}", diesel::debug_query::<Pg, _>(&query));
|
||||||
query
|
query
|
||||||
.execute(conn)
|
.execute(conn)
|
||||||
|
@ -109,6 +109,12 @@ table! {
|
|||||||
///
|
///
|
||||||
/// (Automatically generated by Diesel.)
|
/// (Automatically generated by Diesel.)
|
||||||
bind_token -> Uuid,
|
bind_token -> Uuid,
|
||||||
|
/// The `role` column of the `invitations` table.
|
||||||
|
///
|
||||||
|
/// Its SQL type is `UserRoleType`.
|
||||||
|
///
|
||||||
|
/// (Automatically generated by Diesel.)
|
||||||
|
role -> UserRoleType,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use futures::executor::block_on;
|
use futures::executor::block_on;
|
||||||
|
|
||||||
use jirs_data::{EmailString, InvitationId, UsernameString, WsMsg};
|
use jirs_data::{EmailString, InvitationId, UserRole, UsernameString, WsMsg};
|
||||||
|
|
||||||
use crate::db::invitations;
|
use crate::db::invitations;
|
||||||
use crate::ws::{WebSocketActor, WsHandler, WsResult};
|
use crate::ws::{WebSocketActor, WsHandler, WsResult};
|
||||||
@ -31,6 +31,7 @@ impl WsHandler<ListInvitation> for WebSocketActor {
|
|||||||
pub struct CreateInvitation {
|
pub struct CreateInvitation {
|
||||||
pub email: EmailString,
|
pub email: EmailString,
|
||||||
pub name: UsernameString,
|
pub name: UsernameString,
|
||||||
|
pub role: UserRole,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WsHandler<CreateInvitation> for WebSocketActor {
|
impl WsHandler<CreateInvitation> for WebSocketActor {
|
||||||
@ -45,12 +46,13 @@ impl WsHandler<CreateInvitation> for WebSocketActor {
|
|||||||
_ => return Ok(None),
|
_ => return Ok(None),
|
||||||
};
|
};
|
||||||
|
|
||||||
let CreateInvitation { email, name } = msg;
|
let CreateInvitation { email, name, role } = msg;
|
||||||
let invitation = match block_on(self.db.send(invitations::CreateInvitation {
|
let invitation = match block_on(self.db.send(invitations::CreateInvitation {
|
||||||
user_id,
|
user_id,
|
||||||
project_id,
|
project_id,
|
||||||
email,
|
email,
|
||||||
name,
|
name,
|
||||||
|
role,
|
||||||
})) {
|
})) {
|
||||||
Ok(Ok(invitation)) => invitation,
|
Ok(Ok(invitation)) => invitation,
|
||||||
Ok(Err(e)) => {
|
Ok(Err(e)) => {
|
||||||
|
@ -20,6 +20,7 @@ use crate::ws::invitations::*;
|
|||||||
use crate::ws::issue_statuses::*;
|
use crate::ws::issue_statuses::*;
|
||||||
use crate::ws::issues::*;
|
use crate::ws::issues::*;
|
||||||
use crate::ws::projects::*;
|
use crate::ws::projects::*;
|
||||||
|
use crate::ws::user_projects::LoadUserProjects;
|
||||||
use crate::ws::users::*;
|
use crate::ws::users::*;
|
||||||
|
|
||||||
pub mod auth;
|
pub mod auth;
|
||||||
@ -121,8 +122,12 @@ impl WebSocketActor {
|
|||||||
|
|
||||||
// projects
|
// projects
|
||||||
WsMsg::ProjectRequest => self.handle_msg(CurrentProject, ctx)?,
|
WsMsg::ProjectRequest => self.handle_msg(CurrentProject, ctx)?,
|
||||||
|
WsMsg::ProjectsLoad => self.handle_msg(LoadProjects, ctx)?,
|
||||||
WsMsg::ProjectUpdateRequest(payload) => self.handle_msg(payload, ctx)?,
|
WsMsg::ProjectUpdateRequest(payload) => self.handle_msg(payload, ctx)?,
|
||||||
|
|
||||||
|
// user projects
|
||||||
|
WsMsg::UserProjectLoad => self.handle_msg(LoadUserProjects, ctx)?,
|
||||||
|
|
||||||
// auth
|
// auth
|
||||||
WsMsg::AuthorizeRequest(uuid) => {
|
WsMsg::AuthorizeRequest(uuid) => {
|
||||||
self.handle_msg(CheckAuthToken { token: uuid }, ctx)?
|
self.handle_msg(CheckAuthToken { token: uuid }, ctx)?
|
||||||
@ -157,8 +162,8 @@ impl WebSocketActor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// invitations
|
// invitations
|
||||||
WsMsg::InvitationSendRequest { name, email } => {
|
WsMsg::InvitationSendRequest { name, email, role } => {
|
||||||
self.handle_msg(CreateInvitation { name, email }, ctx)?
|
self.handle_msg(CreateInvitation { name, email, role }, ctx)?
|
||||||
}
|
}
|
||||||
WsMsg::InvitationListRequest => self.handle_msg(ListInvitation, ctx)?,
|
WsMsg::InvitationListRequest => self.handle_msg(ListInvitation, ctx)?,
|
||||||
WsMsg::InvitationAcceptRequest(id) => self.handle_msg(AcceptInvitation { id }, ctx)?,
|
WsMsg::InvitationAcceptRequest(id) => self.handle_msg(AcceptInvitation { id }, ctx)?,
|
||||||
|
@ -2,6 +2,7 @@ use futures::executor::block_on;
|
|||||||
|
|
||||||
use jirs_data::{UpdateProjectPayload, WsMsg};
|
use jirs_data::{UpdateProjectPayload, WsMsg};
|
||||||
|
|
||||||
|
use crate::db;
|
||||||
use crate::db::projects::LoadCurrentProject;
|
use crate::db::projects::LoadCurrentProject;
|
||||||
use crate::ws::{WebSocketActor, WsHandler, WsResult};
|
use crate::ws::{WebSocketActor, WsHandler, WsResult};
|
||||||
|
|
||||||
@ -50,3 +51,22 @@ impl WsHandler<UpdateProjectPayload> for WebSocketActor {
|
|||||||
Ok(Some(WsMsg::ProjectLoaded(project)))
|
Ok(Some(WsMsg::ProjectLoaded(project)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct LoadProjects;
|
||||||
|
|
||||||
|
impl WsHandler<LoadProjects> for WebSocketActor {
|
||||||
|
fn handle_msg(&mut self, _msg: LoadProjects, _ctx: &mut Self::Context) -> WsResult {
|
||||||
|
let user_id = self.require_user()?.id;
|
||||||
|
match block_on(self.db.send(db::projects::LoadProjects { user_id })) {
|
||||||
|
Ok(Ok(v)) => Ok(Some(WsMsg::ProjectsLoaded(v))),
|
||||||
|
Ok(Err(e)) => {
|
||||||
|
error!("{:?}", e);
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
error!("{:?}", e);
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user