Refactor messages

This commit is contained in:
Adrian Woźniak 2021-08-13 17:11:25 +02:00
parent 2d79c91087
commit 02145de39f
No known key found for this signature in database
GPG Key ID: DE43476F72AD3F6C
34 changed files with 807 additions and 501 deletions

18
Cargo.lock generated
View File

@ -1737,38 +1737,21 @@ version = "0.1.0"
dependencies = [ dependencies = [
"actix", "actix",
"amazon-actor", "amazon-actor",
"async-trait",
"bigdecimal",
"bincode",
"bitflags",
"byteorder",
"chrono",
"common", "common",
"database-actor", "database-actor",
"dotenv", "dotenv",
"env_logger",
"filesystem-actor", "filesystem-actor",
"futures", "futures",
"highlight-actor", "highlight-actor",
"ipnetwork 0.16.0",
"jirs-config", "jirs-config",
"jirs-data", "jirs-data",
"libc", "libc",
"log",
"mail-actor", "mail-actor",
"num-bigint",
"num-integer",
"num-traits",
"openssl-sys", "openssl-sys",
"percent-encoding",
"pretty_env_logger",
"serde", "serde",
"serde_json", "serde_json",
"time 0.1.43",
"tokio 0.2.25", "tokio 0.2.25",
"toml", "toml",
"url",
"uuid 0.8.2",
"web-actor", "web-actor",
"websocket-actor", "websocket-actor",
] ]
@ -3968,6 +3951,7 @@ name = "websocket-actor"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"actix", "actix",
"async-trait",
"bincode", "bincode",
"common", "common",
"comrak", "comrak",

View File

@ -30,6 +30,8 @@ lazy_static = { version = "*" }
uuid = { version = "0.8.1", features = ["serde", "v4", "v5"] } uuid = { version = "0.8.1", features = ["serde", "v4", "v5"] }
async-trait = { version = "*" }
[dependencies.comrak] [dependencies.comrak]
version = "*" version = "*"

View File

@ -15,24 +15,25 @@ pub struct Authenticate {
pub email: String, pub email: String,
} }
impl WsHandler<Authenticate> for WebSocketActor { #[async_trait::async_trait]
fn handle_msg(&mut self, msg: Authenticate, _ctx: &mut Self::Context) -> WsResult { impl AsyncHandler<Authenticate> for WebSocketActor {
async fn exec(&mut self, msg: Authenticate) -> WsResult {
let Authenticate { name, email } = msg; let Authenticate { name, email } = msg;
// TODO check attempt number, allow only 5 times per day // TODO check attempt number, allow only 5 times per day
let user = db_or_debug_and_return!( let user = db_or_debug_and_return!(
self, self,
LookupUser { name, email }, LookupUser { name, email },
Ok(Some(WsMsg::Error(WsError::InvalidLoginPair))), Ok(Some(WsMsg::Error(WsError::InvalidLoginPair))),
Ok(Some(WsMsg::Error(WsError::InvalidLoginPair))) Ok(Some(WsMsg::Error(WsError::InvalidLoginPair))); async
); );
let token = db_or_debug_and_return!(self, CreateBindToken { user_id: user.id });
let token = db_or_debug_and_return!(self, CreateBindToken { user_id: user.id }; async);
if let Some(bind_token) = token.bind_token.as_ref().cloned() { if let Some(bind_token) = token.bind_token.as_ref().cloned() {
let _ = mail_or_debug_and_return!( let _ = mail_or_debug_and_return!(
self, self,
Welcome { Welcome {bind_token,
bind_token,
email: user.email, email: user.email,
} }; async
); );
} }
Ok(Some(WsMsg::AuthenticateSuccess)) Ok(Some(WsMsg::AuthenticateSuccess))
@ -76,15 +77,16 @@ pub struct CheckBindToken {
pub bind_token: uuid::Uuid, pub bind_token: uuid::Uuid,
} }
impl WsHandler<CheckBindToken> for WebSocketActor { #[async_trait::async_trait]
fn handle_msg(&mut self, msg: CheckBindToken, _ctx: &mut Self::Context) -> WsResult { impl AsyncHandler<CheckBindToken> for WebSocketActor {
async fn exec(&mut self, msg: CheckBindToken) -> WsResult {
let token: Token = db_or_debug_and_return!( let token: Token = db_or_debug_and_return!(
self, self,
FindBindToken { FindBindToken {
token: msg.bind_token, token: msg.bind_token,
}, },
Ok(Some(WsMsg::BindTokenBad)), Ok(Some(WsMsg::BindTokenBad)),
Ok(None) Ok(None); async
); );
Ok(Some(WsMsg::BindTokenOk(token.access_token))) Ok(Some(WsMsg::BindTokenOk(token.access_token)))
} }

View File

@ -1,29 +1,53 @@
use futures::executor::block_on; use jirs_data::msg::WsMsgComment;
use jirs_data::{CommentId, CreateCommentPayload, IssueId, UpdateCommentPayload, WsMsg}; use jirs_data::{CommentId, CreateCommentPayload, IssueId, UpdateCommentPayload, WsMsg};
use crate::{db_or_debug_and_return, WebSocketActor, WsHandler, WsResult}; use crate::{db_or_debug_and_return, AsyncHandler, WebSocketActor, WsResult};
#[async_trait::async_trait]
impl AsyncHandler<WsMsgComment> for WebSocketActor {
async fn exec(&mut self, msg: WsMsgComment) -> WsResult {
match msg {
WsMsgComment::IssueCommentsLoad(issue_id) => {
self.exec(LoadIssueComments { issue_id }).await
}
WsMsgComment::CommentCreate(payload) => self.exec(payload).await,
WsMsgComment::CommentUpdate(payload) => self.exec(payload).await,
WsMsgComment::CommentDelete(comment_id) => {
self.exec(DeleteComment { comment_id }).await
}
WsMsgComment::IssueCommentsLoaded(_) => Ok(None),
WsMsgComment::CommentCreated(_) => Ok(None),
WsMsgComment::CommentUpdated(_) => Ok(None),
WsMsgComment::CommentDeleted(_, _) => Ok(None),
}
}
}
pub struct LoadIssueComments { pub struct LoadIssueComments {
pub issue_id: IssueId, pub issue_id: IssueId,
} }
impl WsHandler<LoadIssueComments> for WebSocketActor { #[async_trait::async_trait]
fn handle_msg(&mut self, msg: LoadIssueComments, _ctx: &mut Self::Context) -> WsResult { impl AsyncHandler<LoadIssueComments> for WebSocketActor {
async fn exec(&mut self, msg: LoadIssueComments) -> WsResult {
self.require_user()?; self.require_user()?;
let comments = db_or_debug_and_return!( let comments = db_or_debug_and_return!(
self, self,
database_actor::comments::LoadIssueComments { database_actor::comments::LoadIssueComments {
issue_id: msg.issue_id, issue_id: msg.issue_id,
} }; async
); );
Ok(Some(WsMsg::IssueCommentsLoaded(comments))) Ok(Some(WsMsg::Comment(WsMsgComment::IssueCommentsLoaded(
comments,
))))
} }
} }
impl WsHandler<CreateCommentPayload> for WebSocketActor { #[async_trait::async_trait]
fn handle_msg(&mut self, mut msg: CreateCommentPayload, ctx: &mut Self::Context) -> WsResult { impl AsyncHandler<CreateCommentPayload> for WebSocketActor {
async fn exec(&mut self, mut msg: CreateCommentPayload) -> WsResult {
use database_actor::comments::CreateComment; use database_actor::comments::CreateComment;
let user_id = self.require_user()?.id; let user_id = self.require_user()?.id;
@ -37,14 +61,15 @@ impl WsHandler<CreateCommentPayload> for WebSocketActor {
user_id, user_id,
issue_id, issue_id,
body: msg.body, body: msg.body,
} }; async
); );
self.handle_msg(LoadIssueComments { issue_id }, ctx) self.exec(LoadIssueComments { issue_id }).await
} }
} }
impl WsHandler<UpdateCommentPayload> for WebSocketActor { #[async_trait::async_trait]
fn handle_msg(&mut self, msg: UpdateCommentPayload, _ctx: &mut Self::Context) -> WsResult { impl AsyncHandler<UpdateCommentPayload> for WebSocketActor {
async fn exec(&mut self, msg: UpdateCommentPayload) -> WsResult {
use database_actor::comments::UpdateComment; use database_actor::comments::UpdateComment;
let user_id = self.require_user()?.id; let user_id = self.require_user()?.id;
@ -60,9 +85,9 @@ impl WsHandler<UpdateCommentPayload> for WebSocketActor {
comment_id, comment_id,
user_id, user_id,
body, body,
} }; async
); );
self.broadcast(&WsMsg::CommentUpdated(comment)); self.broadcast(&WsMsg::Comment(WsMsgComment::CommentUpdated(comment)));
Ok(None) Ok(None)
} }
} }
@ -71,8 +96,9 @@ pub struct DeleteComment {
pub comment_id: CommentId, pub comment_id: CommentId,
} }
impl WsHandler<DeleteComment> for WebSocketActor { #[async_trait::async_trait]
fn handle_msg(&mut self, msg: DeleteComment, _ctx: &mut Self::Context) -> WsResult { impl AsyncHandler<DeleteComment> for WebSocketActor {
async fn exec(&mut self, msg: DeleteComment) -> WsResult {
use database_actor::comments::DeleteComment; use database_actor::comments::DeleteComment;
let user_id = self.require_user()?.id; let user_id = self.require_user()?.id;
@ -82,8 +108,11 @@ impl WsHandler<DeleteComment> for WebSocketActor {
DeleteComment { DeleteComment {
comment_id: msg.comment_id, comment_id: msg.comment_id,
user_id, user_id,
} }; async
); );
Ok(Some(WsMsg::CommentDeleted(msg.comment_id, n))) Ok(Some(WsMsg::Comment(WsMsgComment::CommentDeleted(
msg.comment_id,
n,
))))
} }
} }

View File

@ -1,17 +1,59 @@
use futures::executor::block_on; use jirs_data::msg::{WsMsgEpic, WsMsgIssue};
use jirs_data::{ use jirs_data::{
DescriptionString, EndsAt, EpicId, IssueType, NameString, StartsAt, UserProject, WsMsg, DescriptionString, EndsAt, EpicId, IssueType, NameString, StartsAt, UserProject, WsMsg,
}; };
use crate::{db_or_debug_and_return, *}; use crate::{db_or_debug_and_return, *};
#[async_trait::async_trait]
impl AsyncHandler<WsMsgEpic> for WebSocketActor {
async fn exec(&mut self, msg: WsMsgEpic) -> WsResult {
match msg {
WsMsgEpic::EpicsLoad => self.exec(epics::LoadEpics).await,
WsMsgEpic::EpicCreate(name, description, description_html) => {
self.exec(epics::CreateEpic {
name,
description,
description_html,
})
.await
}
WsMsgEpic::EpicUpdateName(epic_id, name) => {
self.exec(epics::UpdateEpicName { epic_id, name }).await
}
WsMsgEpic::EpicUpdateStartsAt(epic_id, starts_at) => {
self.exec(epics::UpdateEpicStartsAt { epic_id, starts_at })
.await
}
WsMsgEpic::EpicUpdateEndsAt(epic_id, ends_at) => {
self.exec(epics::UpdateEpicEndsAt { epic_id, ends_at })
.await
}
WsMsgEpic::EpicDelete(epic_id) => self.exec(epics::DeleteEpic { epic_id }).await,
WsMsgEpic::EpicTransform(epic_id, issue_type) => {
self.exec(epics::TransformEpic {
epic_id,
issue_type,
})
.await
}
WsMsgEpic::EpicsLoaded(_) => Ok(None),
WsMsgEpic::EpicCreated(_) => Ok(None),
WsMsgEpic::EpicUpdated(_) => Ok(None),
WsMsgEpic::EpicDeleted(_, _) => Ok(None),
}
}
}
pub struct LoadEpics; pub struct LoadEpics;
impl WsHandler<LoadEpics> for WebSocketActor { #[async_trait::async_trait]
fn handle_msg(&mut self, _msg: LoadEpics, _ctx: &mut Self::Context) -> WsResult { impl AsyncHandler<LoadEpics> for WebSocketActor {
async fn exec(&mut self, _msg: LoadEpics) -> WsResult {
let project_id = self.require_user_project()?.project_id; let project_id = self.require_user_project()?.project_id;
let epics = db_or_debug_and_return!(self, database_actor::epics::LoadEpics { project_id }); let epics =
Ok(Some(WsMsg::EpicsLoaded(epics))) db_or_debug_and_return!(self, database_actor::epics::LoadEpics { project_id }; async);
Ok(Some(WsMsg::Epic(WsMsgEpic::EpicsLoaded(epics))))
} }
} }
@ -21,8 +63,9 @@ pub struct CreateEpic {
pub description_html: Option<DescriptionString>, pub description_html: Option<DescriptionString>,
} }
impl WsHandler<CreateEpic> for WebSocketActor { #[async_trait::async_trait]
fn handle_msg(&mut self, msg: CreateEpic, _ctx: &mut Self::Context) -> WsResult { impl AsyncHandler<CreateEpic> for WebSocketActor {
async fn exec(&mut self, msg: CreateEpic) -> WsResult {
let CreateEpic { let CreateEpic {
name, name,
description, description,
@ -41,9 +84,9 @@ impl WsHandler<CreateEpic> for WebSocketActor {
description, description,
description_html, description_html,
name, name,
} }; async
); );
Ok(Some(WsMsg::EpicCreated(epic))) Ok(Some(WsMsg::Epic(WsMsgEpic::EpicCreated(epic))))
} }
} }
@ -52,8 +95,9 @@ pub struct UpdateEpicName {
pub name: NameString, pub name: NameString,
} }
impl WsHandler<UpdateEpicName> for WebSocketActor { #[async_trait::async_trait]
fn handle_msg(&mut self, msg: UpdateEpicName, _ctx: &mut Self::Context) -> WsResult { impl AsyncHandler<UpdateEpicName> for WebSocketActor {
async fn exec(&mut self, msg: UpdateEpicName) -> WsResult {
let UserProject { project_id, .. } = self.require_user_project()?; let UserProject { project_id, .. } = self.require_user_project()?;
let epic = db_or_debug_and_return!( let epic = db_or_debug_and_return!(
self, self,
@ -61,9 +105,9 @@ impl WsHandler<UpdateEpicName> for WebSocketActor {
project_id: *project_id, project_id: *project_id,
epic_id: msg.epic_id, epic_id: msg.epic_id,
name: msg.name, name: msg.name,
} }; async
); );
Ok(Some(WsMsg::EpicUpdated(epic))) Ok(Some(WsMsg::Epic(WsMsgEpic::EpicUpdated(epic))))
} }
} }
@ -72,8 +116,9 @@ pub struct UpdateEpicStartsAt {
pub starts_at: Option<StartsAt>, pub starts_at: Option<StartsAt>,
} }
impl WsHandler<UpdateEpicStartsAt> for WebSocketActor { #[async_trait::async_trait]
fn handle_msg(&mut self, msg: UpdateEpicStartsAt, _ctx: &mut Self::Context) -> WsResult { impl AsyncHandler<UpdateEpicStartsAt> for WebSocketActor {
async fn exec(&mut self, msg: UpdateEpicStartsAt) -> WsResult {
let UserProject { project_id, .. } = self.require_user_project()?; let UserProject { project_id, .. } = self.require_user_project()?;
let epic = db_or_debug_and_return!( let epic = db_or_debug_and_return!(
self, self,
@ -81,9 +126,9 @@ impl WsHandler<UpdateEpicStartsAt> for WebSocketActor {
project_id: *project_id, project_id: *project_id,
epic_id: msg.epic_id, epic_id: msg.epic_id,
starts_at: msg.starts_at, starts_at: msg.starts_at,
} }; async
); );
Ok(Some(WsMsg::EpicUpdated(epic))) Ok(Some(WsMsg::Epic(WsMsgEpic::EpicUpdated(epic))))
} }
} }
@ -92,8 +137,9 @@ pub struct UpdateEpicEndsAt {
pub ends_at: Option<EndsAt>, pub ends_at: Option<EndsAt>,
} }
impl WsHandler<UpdateEpicEndsAt> for WebSocketActor { #[async_trait::async_trait]
fn handle_msg(&mut self, msg: UpdateEpicEndsAt, _ctx: &mut Self::Context) -> WsResult { impl AsyncHandler<UpdateEpicEndsAt> for WebSocketActor {
async fn exec(&mut self, msg: UpdateEpicEndsAt) -> WsResult {
let UserProject { project_id, .. } = self.require_user_project()?; let UserProject { project_id, .. } = self.require_user_project()?;
let epic = db_or_debug_and_return!( let epic = db_or_debug_and_return!(
self, self,
@ -101,9 +147,9 @@ impl WsHandler<UpdateEpicEndsAt> for WebSocketActor {
project_id: *project_id, project_id: *project_id,
epic_id: msg.epic_id, epic_id: msg.epic_id,
ends_at: msg.ends_at, ends_at: msg.ends_at,
} }; async
); );
Ok(Some(WsMsg::EpicUpdated(epic))) Ok(Some(WsMsg::Epic(WsMsgEpic::EpicUpdated(epic))))
} }
} }
@ -111,8 +157,9 @@ pub struct DeleteEpic {
pub epic_id: EpicId, pub epic_id: EpicId,
} }
impl WsHandler<DeleteEpic> for WebSocketActor { #[async_trait::async_trait]
fn handle_msg(&mut self, msg: DeleteEpic, _ctx: &mut Self::Context) -> WsResult { impl AsyncHandler<DeleteEpic> for WebSocketActor {
async fn exec(&mut self, msg: DeleteEpic) -> WsResult {
let DeleteEpic { epic_id } = msg; let DeleteEpic { epic_id } = msg;
let UserProject { user_id, .. } = self.require_user_project()?; let UserProject { user_id, .. } = self.require_user_project()?;
let n = db_or_debug_and_return!( let n = db_or_debug_and_return!(
@ -120,9 +167,9 @@ impl WsHandler<DeleteEpic> for WebSocketActor {
database_actor::epics::DeleteEpic { database_actor::epics::DeleteEpic {
user_id: *user_id, user_id: *user_id,
epic_id, epic_id,
} }; async
); );
Ok(Some(WsMsg::EpicDeleted(epic_id, n))) Ok(Some(WsMsg::Epic(WsMsgEpic::EpicDeleted(epic_id, n))))
} }
} }
@ -131,13 +178,14 @@ pub struct TransformEpic {
pub issue_type: IssueType, pub issue_type: IssueType,
} }
impl WsHandler<TransformEpic> for WebSocketActor { #[async_trait::async_trait]
fn handle_msg(&mut self, msg: TransformEpic, _ctx: &mut Self::Context) -> WsResult { impl AsyncHandler<TransformEpic> for WebSocketActor {
async fn exec(&mut self, msg: TransformEpic) -> WsResult {
let epic: jirs_data::Epic = db_or_debug_and_return!( let epic: jirs_data::Epic = db_or_debug_and_return!(
self, self,
database_actor::epics::FindEpic { database_actor::epics::FindEpic {
epic_id: msg.epic_id epic_id: msg.epic_id
} }; async
); );
let issue: database_actor::models::Issue = db_or_debug_and_return!( let issue: database_actor::models::Issue = db_or_debug_and_return!(
self, self,
@ -155,17 +203,17 @@ impl WsHandler<TransformEpic> for WebSocketActor {
reporter_id: epic.user_id, reporter_id: epic.user_id,
user_ids: vec![epic.user_id], user_ids: vec![epic.user_id],
epic_id: None epic_id: None
} }; async
); );
let n = db_or_debug_and_return!( let n = db_or_debug_and_return!(
self, self,
database_actor::epics::DeleteEpic { database_actor::epics::DeleteEpic {
user_id: epic.user_id, user_id: epic.user_id,
epic_id: epic.id epic_id: epic.id
} }; async
); );
self.broadcast(&WsMsg::EpicDeleted(msg.epic_id, n)); self.broadcast(&WsMsg::Epic(WsMsgEpic::EpicDeleted(msg.epic_id, n)));
self.broadcast(&WsMsg::IssueCreated(issue.into())); self.broadcast(&WsMsg::Issue(WsMsgIssue::IssueCreated(issue.into())));
Ok(None) Ok(None)
} }
} }

View File

@ -1,12 +1,12 @@
use futures::executor::block_on;
use jirs_data::{Code, Lang, WsMsg}; use jirs_data::{Code, Lang, WsMsg};
use crate::{actor_or_debug_and_return, WebSocketActor, WsHandler, WsResult}; use crate::{actor_or_debug_and_return, AsyncHandler, WebSocketActor, WsResult};
pub struct HighlightCode(pub Lang, pub Code); pub struct HighlightCode(pub Lang, pub Code);
impl WsHandler<HighlightCode> for WebSocketActor { #[async_trait::async_trait]
fn handle_msg(&mut self, msg: HighlightCode, _ctx: &mut Self::Context) -> WsResult { impl AsyncHandler<HighlightCode> for WebSocketActor {
async fn exec(&mut self, msg: HighlightCode) -> WsResult {
self.require_user()?; self.require_user()?;
let res = actor_or_debug_and_return!( let res = actor_or_debug_and_return!(
self, self,
@ -14,7 +14,7 @@ impl WsHandler<HighlightCode> for WebSocketActor {
highlight_actor::HighlightCode { highlight_actor::HighlightCode {
code: msg.1, code: msg.1,
lang: msg.0, lang: msg.0,
} }; async
); );
Ok(Some(WsMsg::HighlightedCode(res))) Ok(Some(WsMsg::HighlightedCode(res)))
} }

View File

@ -1,26 +1,64 @@
use database_actor::invitations; use database_actor::invitations;
use database_actor::messages::CreateMessageReceiver; use database_actor::messages::CreateMessageReceiver;
use futures::executor::block_on; use futures::executor::block_on;
use jirs_data::msg::WsMsgInvitation;
use jirs_data::{ use jirs_data::{
EmailString, InvitationId, InvitationToken, MessageType, UserRole, UsernameString, WsMsg, EmailString, InvitationId, InvitationToken, MessageType, UserRole, UsernameString, WsMsg,
}; };
use crate::handlers::{LoadInvitedUsers, RemoveInvitedUser};
use crate::server::InnerMsg; use crate::server::InnerMsg;
use crate::{ use crate::{
db_or_debug_and_return, mail_or_debug_and_return, WebSocketActor, WsHandler, WsMessageSender, db_or_debug_and_return, mail_or_debug_and_return, AsyncHandler, WebSocketActor, WsHandler,
WsResult, WsMessageSender, WsResult,
}; };
#[async_trait::async_trait]
impl AsyncHandler<WsMsgInvitation> for WebSocketActor {
async fn exec(&mut self, msg: WsMsgInvitation) -> WsResult {
match msg {
WsMsgInvitation::InvitationSendRequest { name, email, role } => {
self.exec(CreateInvitation { email, name, role }).await
}
WsMsgInvitation::InvitationListLoad => self.exec(ListInvitation).await,
WsMsgInvitation::InvitationRevokeRequest(id) => {
self.exec(RevokeInvitation { id }).await
}
WsMsgInvitation::InvitedUsersLoad => self.exec(LoadInvitedUsers).await,
WsMsgInvitation::InvitedUserRemoveRequest(user_id) => {
self.exec(RemoveInvitedUser { user_id }).await
}
WsMsgInvitation::InvitationListLoaded(_) => Ok(None),
WsMsgInvitation::InvitedUsersLoaded(_) => Ok(None),
WsMsgInvitation::InvitationSendSuccess => Ok(None),
WsMsgInvitation::InvitationSendFailure => Ok(None),
WsMsgInvitation::InvitationRevokeSuccess(_) => Ok(None),
WsMsgInvitation::InvitationAcceptRequest(_) => Ok(None),
WsMsgInvitation::InvitationAcceptSuccess(_) => Ok(None),
WsMsgInvitation::InvitationAcceptFailure(_) => Ok(None),
WsMsgInvitation::InvitationRejectRequest(_) => Ok(None),
WsMsgInvitation::InvitationRejectSuccess => Ok(None),
WsMsgInvitation::InvitationRejectFailure(_) => Ok(None),
WsMsgInvitation::InvitedUserRemoveSuccess(_) => Ok(None),
}
}
}
pub struct ListInvitation; pub struct ListInvitation;
impl WsHandler<ListInvitation> for WebSocketActor { #[async_trait::async_trait]
fn handle_msg(&mut self, _msg: ListInvitation, _ctx: &mut Self::Context) -> WsResult { impl AsyncHandler<ListInvitation> for WebSocketActor {
async fn exec(&mut self, _msg: ListInvitation) -> WsResult {
let user_id = match self.current_user.as_ref().map(|u| u.id) { let user_id = match self.current_user.as_ref().map(|u| u.id) {
Some(id) => id, Some(id) => id,
_ => return Ok(None), _ => return Ok(None),
}; };
let v = db_or_debug_and_return!(self, invitations::ListInvitation { user_id }); let v = db_or_debug_and_return!(self, invitations::ListInvitation { user_id }; async);
Ok(Some(WsMsg::InvitationListLoaded(v))) Ok(Some(WsMsg::Invitation(
WsMsgInvitation::InvitationListLoaded(v),
)))
} }
} }
@ -30,8 +68,9 @@ pub struct CreateInvitation {
pub role: UserRole, pub role: UserRole,
} }
impl WsHandler<CreateInvitation> for WebSocketActor { #[async_trait::async_trait]
fn handle_msg(&mut self, msg: CreateInvitation, _ctx: &mut Self::Context) -> WsResult { impl AsyncHandler<CreateInvitation> for WebSocketActor {
async fn exec(&mut self, msg: CreateInvitation) -> WsResult {
let project_id = match self.current_user_project.as_ref() { let project_id = match self.current_user_project.as_ref() {
Some(up) => up.project_id, Some(up) => up.project_id,
_ => return Ok(None), _ => return Ok(None),
@ -48,8 +87,8 @@ impl WsHandler<CreateInvitation> for WebSocketActor {
name: name.clone(), name: name.clone(),
role, role,
}, },
Ok(Some(WsMsg::InvitationSendFailure)), Ok(Some(WsMsg::Invitation(WsMsgInvitation::InvitationSendFailure))),
Ok(Some(WsMsg::InvitationSendFailure)) Ok(Some(WsMsg::Invitation(WsMsgInvitation::InvitationSendFailure))); async
); );
let _ = mail_or_debug_and_return!( let _ = mail_or_debug_and_return!(
self, self,
@ -58,8 +97,8 @@ impl WsHandler<CreateInvitation> for WebSocketActor {
email: invitation.email, email: invitation.email,
inviter_name, inviter_name,
}, },
Ok(Some(WsMsg::InvitationSendFailure)), Ok(Some(WsMsg::Invitation(WsMsgInvitation::InvitationSendFailure))),
Ok(Some(WsMsg::InvitationSendFailure)) Ok(Some(WsMsg::Invitation(WsMsgInvitation::InvitationSendFailure))); async
); );
// If user exists then send message to him // If user exists then send message to him
@ -77,7 +116,9 @@ impl WsHandler<CreateInvitation> for WebSocketActor {
)); ));
} }
Ok(Some(WsMsg::InvitationSendSuccess)) Ok(Some(WsMsg::Invitation(
WsMsgInvitation::InvitationSendSuccess,
)))
} }
} }
@ -85,11 +126,12 @@ pub struct DeleteInvitation {
pub id: InvitationId, pub id: InvitationId,
} }
impl WsHandler<DeleteInvitation> for WebSocketActor { #[async_trait::async_trait]
fn handle_msg(&mut self, msg: DeleteInvitation, _ctx: &mut Self::Context) -> WsResult { impl AsyncHandler<DeleteInvitation> for WebSocketActor {
async fn exec(&mut self, msg: DeleteInvitation) -> WsResult {
self.require_user()?; self.require_user()?;
let DeleteInvitation { id } = msg; let DeleteInvitation { id } = msg;
let _ = db_or_debug_and_return!(self, invitations::DeleteInvitation { id }); let _ = db_or_debug_and_return!(self, invitations::DeleteInvitation { id }; async);
Ok(None) Ok(None)
} }
} }
@ -98,12 +140,15 @@ pub struct RevokeInvitation {
pub id: InvitationId, pub id: InvitationId,
} }
impl WsHandler<RevokeInvitation> for WebSocketActor { #[async_trait::async_trait]
fn handle_msg(&mut self, msg: RevokeInvitation, _ctx: &mut Self::Context) -> WsResult { impl AsyncHandler<RevokeInvitation> for WebSocketActor {
async fn exec(&mut self, msg: RevokeInvitation) -> WsResult {
self.require_user()?; self.require_user()?;
let RevokeInvitation { id } = msg; let RevokeInvitation { id } = msg;
let _ = db_or_debug_and_return!(self, invitations::RevokeInvitation { id }); let _ = db_or_debug_and_return!(self, invitations::RevokeInvitation { id }; async);
Ok(Some(WsMsg::InvitationRevokeSuccess(id))) Ok(Some(WsMsg::Invitation(
WsMsgInvitation::InvitationRevokeSuccess(id),
)))
} }
} }
@ -117,8 +162,12 @@ impl WsHandler<AcceptInvitation> for WebSocketActor {
let token = db_or_debug_and_return!( let token = db_or_debug_and_return!(
self, self,
invitations::AcceptInvitation { invitation_token }, invitations::AcceptInvitation { invitation_token },
Ok(Some(WsMsg::InvitationAcceptFailure(invitation_token))), Ok(Some(WsMsg::Invitation(
Ok(Some(WsMsg::InvitationAcceptFailure(invitation_token))) WsMsgInvitation::InvitationAcceptFailure(invitation_token)
))),
Ok(Some(WsMsg::Invitation(
WsMsgInvitation::InvitationAcceptFailure(invitation_token)
)))
); );
for message in crate::actor_or_debug_and_fallback!( for message in crate::actor_or_debug_and_fallback!(
@ -144,6 +193,8 @@ impl WsHandler<AcceptInvitation> for WebSocketActor {
); );
} }
Ok(Some(WsMsg::InvitationAcceptSuccess(token.access_token))) Ok(Some(WsMsg::Invitation(
WsMsgInvitation::InvitationAcceptSuccess(token.access_token),
)))
} }
} }

View File

@ -1,17 +1,48 @@
use database_actor::issue_statuses; use database_actor::issue_statuses;
use futures::executor::block_on; use jirs_data::msg::WsMsgIssueStatus;
use jirs_data::{IssueStatusId, Position, TitleString, WsMsg}; use jirs_data::{IssueStatusId, Position, TitleString, WsMsg};
use crate::{db_or_debug_and_return, WebSocketActor, WsHandler, WsResult}; use crate::{db_or_debug_and_return, AsyncHandler, WebSocketActor, WsResult};
#[async_trait::async_trait]
impl AsyncHandler<WsMsgIssueStatus> for WebSocketActor {
async fn exec(&mut self, msg: WsMsgIssueStatus) -> WsResult {
match msg {
WsMsgIssueStatus::IssueStatusesLoad => self.exec(LoadIssueStatuses).await,
WsMsgIssueStatus::IssueStatusDelete(issue_status_id) => {
self.exec(DeleteIssueStatus { issue_status_id }).await
}
WsMsgIssueStatus::IssueStatusUpdate(issue_status_id, name, position) => {
self.exec(UpdateIssueStatus {
issue_status_id,
position,
name,
})
.await
}
WsMsgIssueStatus::IssueStatusCreate(name, position) => {
self.exec(CreateIssueStatus { position, name }).await
}
WsMsgIssueStatus::IssueStatusesLoaded(_) => Ok(None),
WsMsgIssueStatus::IssueStatusUpdated(_) => Ok(None),
WsMsgIssueStatus::IssueStatusCreated(_) => Ok(None),
WsMsgIssueStatus::IssueStatusDeleted(_, _) => Ok(None),
}
}
}
pub struct LoadIssueStatuses; pub struct LoadIssueStatuses;
impl WsHandler<LoadIssueStatuses> for WebSocketActor { #[async_trait::async_trait]
fn handle_msg(&mut self, _msg: LoadIssueStatuses, _ctx: &mut Self::Context) -> WsResult { impl AsyncHandler<LoadIssueStatuses> for WebSocketActor {
async fn exec(&mut self, _msg: LoadIssueStatuses) -> WsResult {
let project_id = self.require_user_project()?.project_id; let project_id = self.require_user_project()?.project_id;
let v = db_or_debug_and_return!(self, issue_statuses::LoadIssueStatuses { project_id }); let v =
Ok(Some(WsMsg::IssueStatusesLoaded(v))) db_or_debug_and_return!(self, issue_statuses::LoadIssueStatuses { project_id }; async);
Ok(Some(WsMsg::IssueStatus(
WsMsgIssueStatus::IssueStatusesLoaded(v),
)))
} }
} }
@ -20,8 +51,9 @@ pub struct CreateIssueStatus {
pub name: TitleString, pub name: TitleString,
} }
impl WsHandler<CreateIssueStatus> for WebSocketActor { #[async_trait::async_trait]
fn handle_msg(&mut self, msg: CreateIssueStatus, _ctx: &mut Self::Context) -> WsResult { impl AsyncHandler<CreateIssueStatus> for WebSocketActor {
async fn exec(&mut self, msg: CreateIssueStatus) -> WsResult {
let project_id = self.require_user_project()?.project_id; let project_id = self.require_user_project()?.project_id;
let CreateIssueStatus { position, name } = msg; let CreateIssueStatus { position, name } = msg;
@ -31,9 +63,11 @@ impl WsHandler<CreateIssueStatus> for WebSocketActor {
project_id, project_id,
position, position,
name, name,
} }; async
); );
Ok(Some(WsMsg::IssueStatusCreated(issue_status))) Ok(Some(WsMsg::IssueStatus(
WsMsgIssueStatus::IssueStatusCreated(issue_status),
)))
} }
} }
@ -41,8 +75,9 @@ pub struct DeleteIssueStatus {
pub issue_status_id: IssueStatusId, pub issue_status_id: IssueStatusId,
} }
impl WsHandler<DeleteIssueStatus> for WebSocketActor { #[async_trait::async_trait]
fn handle_msg(&mut self, msg: DeleteIssueStatus, _ctx: &mut Self::Context) -> WsResult { impl AsyncHandler<DeleteIssueStatus> for WebSocketActor {
async fn exec(&mut self, msg: DeleteIssueStatus) -> WsResult {
let project_id = self.require_user_project()?.project_id; let project_id = self.require_user_project()?.project_id;
let DeleteIssueStatus { issue_status_id } = msg; let DeleteIssueStatus { issue_status_id } = msg;
@ -51,9 +86,11 @@ impl WsHandler<DeleteIssueStatus> for WebSocketActor {
issue_statuses::DeleteIssueStatus { issue_statuses::DeleteIssueStatus {
project_id, project_id,
issue_status_id issue_status_id
} }; async
); );
Ok(Some(WsMsg::IssueStatusDeleted(msg.issue_status_id, n))) Ok(Some(WsMsg::IssueStatus(
WsMsgIssueStatus::IssueStatusDeleted(msg.issue_status_id, n),
)))
} }
} }
@ -63,8 +100,9 @@ pub struct UpdateIssueStatus {
pub name: TitleString, pub name: TitleString,
} }
impl WsHandler<UpdateIssueStatus> for WebSocketActor { #[async_trait::async_trait]
fn handle_msg(&mut self, msg: UpdateIssueStatus, _ctx: &mut Self::Context) -> WsResult { impl AsyncHandler<UpdateIssueStatus> for WebSocketActor {
async fn exec(&mut self, msg: UpdateIssueStatus) -> WsResult {
let project_id = self.require_user_project()?.project_id; let project_id = self.require_user_project()?.project_id;
let UpdateIssueStatus { let UpdateIssueStatus {
@ -79,9 +117,11 @@ impl WsHandler<UpdateIssueStatus> for WebSocketActor {
project_id, project_id,
position, position,
name name
} }; async
); );
let msg = Some(WsMsg::IssueStatusUpdated(issue_status)); let msg = Some(WsMsg::IssueStatus(WsMsgIssueStatus::IssueStatusUpdated(
issue_status,
)));
if let Some(ws_msg) = msg.as_ref() { if let Some(ws_msg) = msg.as_ref() {
self.broadcast(ws_msg) self.broadcast(ws_msg)
} }

View File

@ -2,13 +2,36 @@ use std::collections::HashMap;
use database_actor::issue_assignees::LoadAssignees; use database_actor::issue_assignees::LoadAssignees;
use database_actor::issues::{LoadProjectIssues, UpdateIssue}; use database_actor::issues::{LoadProjectIssues, UpdateIssue};
use futures::executor::block_on; use jirs_data::msg::{WsMsgIssue, WsMsgProject};
use jirs_data::{ use jirs_data::{
CreateIssuePayload, IssueAssignee, IssueFieldId, IssueId, IssueStatusId, ListPosition, CreateIssuePayload, IssueAssignee, IssueFieldId, IssueId, IssueStatusId, ListPosition,
PayloadVariant, WsMsg, PayloadVariant, WsMsg,
}; };
use crate::{db_or_debug_and_return, WebSocketActor, WsHandler, WsResult}; use crate::{db_or_debug_and_return, AsyncHandler, WebSocketActor, WsResult};
#[async_trait::async_trait]
impl AsyncHandler<WsMsgIssue> for WebSocketActor {
async fn exec(&mut self, msg: WsMsgIssue) -> WsResult {
match msg {
WsMsgIssue::IssueUpdate(id, field_id, payload) => {
self.exec(UpdateIssueHandler {
id,
field_id,
payload,
})
.await
}
WsMsgIssue::IssueCreate(payload) => self.exec(payload).await,
WsMsgIssue::IssueDelete(id) => self.exec(DeleteIssue { id }).await,
WsMsgIssue::IssueSyncListPosition(sync) => self.exec(SyncIssueListPosition(sync)).await,
WsMsgIssue::IssueUpdated(_) => Ok(None),
WsMsgIssue::IssueDeleted(_, _) => Ok(None),
WsMsgIssue::IssueCreated(_) => Ok(None),
}
}
}
pub struct UpdateIssueHandler { pub struct UpdateIssueHandler {
pub id: i32, pub id: i32,
@ -16,8 +39,9 @@ pub struct UpdateIssueHandler {
pub payload: PayloadVariant, pub payload: PayloadVariant,
} }
impl WsHandler<UpdateIssueHandler> for WebSocketActor { #[async_trait::async_trait]
fn handle_msg(&mut self, msg: UpdateIssueHandler, _ctx: &mut Self::Context) -> WsResult { impl AsyncHandler<UpdateIssueHandler> for WebSocketActor {
async fn exec(&mut self, msg: UpdateIssueHandler) -> WsResult {
self.require_user()?; self.require_user()?;
let UpdateIssueHandler { let UpdateIssueHandler {
@ -123,23 +147,24 @@ impl WsHandler<UpdateIssueHandler> for WebSocketActor {
_ => (), _ => (),
}; };
let issue = db_or_debug_and_return!(self, msg); let issue = db_or_debug_and_return!(self, msg; async);
let mut issue: jirs_data::Issue = issue.into(); let mut issue: jirs_data::Issue = issue.into();
let assignees: Vec<IssueAssignee> = let assignees: Vec<IssueAssignee> =
db_or_debug_and_return!(self, LoadAssignees { issue_id: issue.id }); db_or_debug_and_return!(self, LoadAssignees { issue_id: issue.id }; async);
for assignee in assignees { for assignee in assignees {
issue.user_ids.push(assignee.user_id); issue.user_ids.push(assignee.user_id);
} }
self.broadcast(&WsMsg::IssueUpdated(issue)); self.broadcast(&WsMsg::Issue(WsMsgIssue::IssueUpdated(issue)));
Ok(None) Ok(None)
} }
} }
impl WsHandler<CreateIssuePayload> for WebSocketActor { #[async_trait::async_trait]
fn handle_msg(&mut self, msg: CreateIssuePayload, _ctx: &mut Self::Context) -> WsResult { impl AsyncHandler<CreateIssuePayload> for WebSocketActor {
async fn exec(&mut self, msg: CreateIssuePayload) -> WsResult {
self.require_user()?; self.require_user()?;
let msg = database_actor::issues::CreateIssue { let msg = database_actor::issues::CreateIssue {
title: msg.title, title: msg.title,
@ -156,8 +181,8 @@ impl WsHandler<CreateIssuePayload> for WebSocketActor {
user_ids: msg.user_ids, user_ids: msg.user_ids,
epic_id: msg.epic_id, epic_id: msg.epic_id,
}; };
let issue = db_or_debug_and_return!(self, msg); let issue = db_or_debug_and_return!(self, msg; async);
Ok(Some(WsMsg::IssueCreated(issue.into()))) Ok(Some(WsMsg::Issue(WsMsgIssue::IssueCreated(issue.into()))))
} }
} }
@ -165,24 +190,26 @@ pub struct DeleteIssue {
pub id: IssueId, pub id: IssueId,
} }
impl WsHandler<DeleteIssue> for WebSocketActor { #[async_trait::async_trait]
fn handle_msg(&mut self, msg: DeleteIssue, _ctx: &mut Self::Context) -> WsResult { impl AsyncHandler<DeleteIssue> for WebSocketActor {
async fn exec(&mut self, msg: DeleteIssue) -> WsResult {
self.require_user()?; self.require_user()?;
let n = db_or_debug_and_return!( let n = db_or_debug_and_return!(
self, self,
database_actor::issues::DeleteIssue { issue_id: msg.id } database_actor::issues::DeleteIssue { issue_id: msg.id }; async
); );
Ok(Some(WsMsg::IssueDeleted(msg.id, n))) Ok(Some(WsMsg::Issue(WsMsgIssue::IssueDeleted(msg.id, n))))
} }
} }
pub struct LoadIssues; pub struct LoadIssues;
impl WsHandler<LoadIssues> for WebSocketActor { #[async_trait::async_trait]
fn handle_msg(&mut self, _msg: LoadIssues, _ctx: &mut Self::Context) -> WsResult { impl AsyncHandler<LoadIssues> for WebSocketActor {
async fn exec(&mut self, _msg: LoadIssues) -> WsResult {
let project_id = self.require_user_project()?.project_id; let project_id = self.require_user_project()?.project_id;
let v = db_or_debug_and_return!(self, LoadProjectIssues { project_id }); let v = db_or_debug_and_return!(self, LoadProjectIssues { project_id }; async);
let issues: Vec<jirs_data::Issue> = v.into_iter().map(|i| i.into()).collect(); let issues: Vec<jirs_data::Issue> = v.into_iter().map(|i| i.into()).collect();
let mut issue_map = HashMap::new(); let mut issue_map = HashMap::new();
let mut queue = vec![]; let mut queue = vec![];
@ -192,7 +219,7 @@ impl WsHandler<LoadIssues> for WebSocketActor {
issue_map.insert(issue.id, issue); issue_map.insert(issue.id, issue);
} }
for f in queue { for f in queue {
if let Ok(Ok(assignees)) = block_on(f) { if let Ok(Ok(assignees)) = f.await {
for assignee in assignees { for assignee in assignees {
if let Some(issue) = issue_map.get_mut(&assignee.issue_id) { if let Some(issue) = issue_map.get_mut(&assignee.issue_id) {
issue.user_ids.push(assignee.user_id); issue.user_ids.push(assignee.user_id);
@ -206,14 +233,17 @@ impl WsHandler<LoadIssues> for WebSocketActor {
} }
issues.sort_by(|a, b| a.list_position.cmp(&b.list_position)); issues.sort_by(|a, b| a.list_position.cmp(&b.list_position));
Ok(Some(WsMsg::ProjectIssuesLoaded(issues))) Ok(Some(WsMsg::Project(WsMsgProject::ProjectIssuesLoaded(
issues,
))))
} }
} }
pub struct SyncIssueListPosition(pub Vec<(IssueId, ListPosition, IssueStatusId, Option<IssueId>)>); pub struct SyncIssueListPosition(pub Vec<(IssueId, ListPosition, IssueStatusId, Option<IssueId>)>);
impl WsHandler<SyncIssueListPosition> for WebSocketActor { #[async_trait::async_trait]
fn handle_msg(&mut self, msg: SyncIssueListPosition, ctx: &mut Self::Context) -> WsResult { impl AsyncHandler<SyncIssueListPosition> for WebSocketActor {
async fn exec(&mut self, msg: SyncIssueListPosition) -> WsResult {
let _project_id = self.require_user_project()?.project_id; let _project_id = self.require_user_project()?.project_id;
for (issue_id, list_position, status_id, epic_id) in msg.0 { for (issue_id, list_position, status_id, epic_id) in msg.0 {
crate::actor_or_debug_and_ignore!( crate::actor_or_debug_and_ignore!(
@ -226,10 +256,10 @@ impl WsHandler<SyncIssueListPosition> for WebSocketActor {
epic_id: Some(epic_id), epic_id: Some(epic_id),
..Default::default() ..Default::default()
}, },
|_| {} |_| {}; async
); );
} }
self.handle_msg(LoadIssues, ctx) self.exec(LoadIssues).await
} }
} }

View File

@ -1,15 +1,15 @@
use database_actor::messages; use database_actor::messages;
use futures::executor::block_on;
use jirs_data::{MessageId, WsMsg}; use jirs_data::{MessageId, WsMsg};
use crate::{db_or_debug_and_return, WebSocketActor, WsHandler, WsResult}; use crate::{db_or_debug_and_return, AsyncHandler, WebSocketActor, WsResult};
pub struct LoadMessages; pub struct LoadMessages;
impl WsHandler<LoadMessages> for WebSocketActor { #[async_trait::async_trait]
fn handle_msg(&mut self, _msg: LoadMessages, _ctx: &mut Self::Context) -> WsResult { impl AsyncHandler<LoadMessages> for WebSocketActor {
async fn exec(&mut self, _msg: LoadMessages) -> WsResult {
let user_id = self.require_user()?.id; let user_id = self.require_user()?.id;
let v = db_or_debug_and_return!(self, messages::LoadMessages { user_id }); let v = db_or_debug_and_return!(self, messages::LoadMessages { user_id }; async);
Ok(Some(WsMsg::MessagesLoaded(v))) Ok(Some(WsMsg::MessagesLoaded(v)))
} }
} }
@ -18,15 +18,16 @@ pub struct MarkMessageSeen {
pub id: MessageId, pub id: MessageId,
} }
impl WsHandler<MarkMessageSeen> for WebSocketActor { #[async_trait::async_trait]
fn handle_msg(&mut self, msg: MarkMessageSeen, _ctx: &mut Self::Context) -> WsResult { impl AsyncHandler<MarkMessageSeen> for WebSocketActor {
async fn exec(&mut self, msg: MarkMessageSeen) -> WsResult {
let user_id = self.require_user()?.id; let user_id = self.require_user()?.id;
let count = db_or_debug_and_return!( let count = db_or_debug_and_return!(
self, self,
messages::MarkMessageSeen { messages::MarkMessageSeen {
message_id: msg.id, message_id: msg.id,
user_id, user_id,
} }; async
); );
Ok(Some(WsMsg::MessageMarkedSeen(msg.id, count))) Ok(Some(WsMsg::MessageMarkedSeen(msg.id, count)))
} }

View File

@ -1,11 +1,28 @@
use database_actor as db; use database_actor as db;
use futures::executor::block_on; use jirs_data::msg::WsMsgProject;
use jirs_data::{UpdateProjectPayload, UserProject, WsMsg}; use jirs_data::{UpdateProjectPayload, UserProject, WsMsg};
use crate::{db_or_debug_and_return, WebSocketActor, WsHandler, WsResult}; use crate::handlers::{LoadIssues, LoadProjectUsers};
use crate::{db_or_debug_and_return, AsyncHandler, WebSocketActor, WsResult};
impl WsHandler<UpdateProjectPayload> for WebSocketActor { #[async_trait::async_trait]
fn handle_msg(&mut self, msg: UpdateProjectPayload, _ctx: &mut Self::Context) -> WsResult { impl AsyncHandler<WsMsgProject> for WebSocketActor {
async fn exec(&mut self, msg: WsMsgProject) -> WsResult {
match msg {
WsMsgProject::ProjectIssuesLoad => self.exec(LoadIssues).await,
WsMsgProject::ProjectsLoad => self.exec(LoadProjects).await,
WsMsgProject::ProjectUpdateLoad(payload) => self.exec(payload).await,
WsMsgProject::ProjectUsersLoad => self.exec(LoadProjectUsers).await,
WsMsgProject::ProjectsLoaded(_) => Ok(None),
WsMsgProject::ProjectIssuesLoaded(_) => Ok(None),
WsMsgProject::ProjectUsersLoaded(_) => Ok(None),
}
}
}
#[async_trait::async_trait]
impl AsyncHandler<UpdateProjectPayload> for WebSocketActor {
async fn exec(&mut self, msg: UpdateProjectPayload) -> WsResult {
let UserProject { let UserProject {
user_id, user_id,
project_id, project_id,
@ -20,22 +37,23 @@ impl WsHandler<UpdateProjectPayload> for WebSocketActor {
description: msg.description, description: msg.description,
category: msg.category, category: msg.category,
time_tracking: msg.time_tracking, time_tracking: msg.time_tracking,
} }; async
); );
let projects = db_or_debug_and_return!( let projects = db_or_debug_and_return!(
self, self,
database_actor::projects::LoadProjects { user_id: *user_id } database_actor::projects::LoadProjects { user_id: *user_id }; async
); );
Ok(Some(WsMsg::ProjectsLoaded(projects))) Ok(Some(WsMsg::Project(WsMsgProject::ProjectsLoaded(projects))))
} }
} }
pub struct LoadProjects; pub struct LoadProjects;
impl WsHandler<LoadProjects> for WebSocketActor { #[async_trait::async_trait]
fn handle_msg(&mut self, _msg: LoadProjects, _ctx: &mut Self::Context) -> WsResult { impl AsyncHandler<LoadProjects> for WebSocketActor {
async fn exec(&mut self, _msg: LoadProjects) -> WsResult {
let user_id = self.require_user()?.id; let user_id = self.require_user()?.id;
let v = db_or_debug_and_return!(self, db::projects::LoadProjects { user_id }); let v = db_or_debug_and_return!(self, db::projects::LoadProjects { user_id }; async);
Ok(Some(WsMsg::ProjectsLoaded(v))) Ok(Some(WsMsg::Project(WsMsgProject::ProjectsLoaded(v))))
} }
} }

View File

@ -1,15 +1,16 @@
use database_actor as db; use database_actor as db;
use futures::executor::block_on;
use jirs_data::{UserProjectId, WsMsg}; use jirs_data::{UserProjectId, WsMsg};
use crate::{db_or_debug_and_return, WebSocketActor, WsHandler, WsResult}; use crate::{db_or_debug_and_return, AsyncHandler, WebSocketActor, WsResult};
pub struct LoadUserProjects; pub struct LoadUserProjects;
impl WsHandler<LoadUserProjects> for WebSocketActor { #[async_trait::async_trait]
fn handle_msg(&mut self, _msg: LoadUserProjects, _ctx: &mut Self::Context) -> WsResult { impl AsyncHandler<LoadUserProjects> for WebSocketActor {
async fn exec(&mut self, _msg: LoadUserProjects) -> WsResult {
let user_id = self.require_user()?.id; let user_id = self.require_user()?.id;
let v = db_or_debug_and_return!(self, db::user_projects::LoadUserProjects { user_id }); let v =
db_or_debug_and_return!(self, db::user_projects::LoadUserProjects { user_id }; async);
Ok(Some(WsMsg::UserProjectsLoaded(v))) Ok(Some(WsMsg::UserProjectsLoaded(v)))
} }
} }
@ -18,15 +19,16 @@ pub struct SetCurrentUserProject {
pub id: UserProjectId, pub id: UserProjectId,
} }
impl WsHandler<SetCurrentUserProject> for WebSocketActor { #[async_trait::async_trait]
fn handle_msg(&mut self, msg: SetCurrentUserProject, _ctx: &mut Self::Context) -> WsResult { impl AsyncHandler<SetCurrentUserProject> for WebSocketActor {
async fn exec(&mut self, msg: SetCurrentUserProject) -> WsResult {
let user_id = self.require_user()?.id; let user_id = self.require_user()?.id;
let user_project = db_or_debug_and_return!( let user_project = db_or_debug_and_return!(
self, self,
db::user_projects::ChangeCurrentUserProject { db::user_projects::ChangeCurrentUserProject {
user_id, user_id,
id: msg.id, id: msg.id,
} }; async
); );
self.current_user_project = Some(user_project.clone()); self.current_user_project = Some(user_project.clone());
Ok(Some(WsMsg::UserProjectCurrentChanged(user_project))) Ok(Some(WsMsg::UserProjectCurrentChanged(user_project)))

View File

@ -1,7 +1,6 @@
use futures::executor::block_on;
use jirs_data::{TextEditorMode, UserId, UserSetting, WsMsg}; use jirs_data::{TextEditorMode, UserId, UserSetting, WsMsg};
use crate::{db_or_debug_and_return, WebSocketActor, WsHandler, WsResult}; use crate::{db_or_debug_and_return, AsyncHandler, WebSocketActor, WsResult};
pub fn default_user_setting(user_id: UserId) -> UserSetting { pub fn default_user_setting(user_id: UserId) -> UserSetting {
UserSetting { UserSetting {
@ -15,15 +14,16 @@ pub struct SetTextEditorMode {
pub mode: TextEditorMode, pub mode: TextEditorMode,
} }
impl WsHandler<SetTextEditorMode> for WebSocketActor { #[async_trait::async_trait]
fn handle_msg(&mut self, msg: SetTextEditorMode, _ctx: &mut Self::Context) -> WsResult { impl AsyncHandler<SetTextEditorMode> for WebSocketActor {
async fn exec(&mut self, msg: SetTextEditorMode) -> WsResult {
let user_id = self.require_user()?.id; let user_id = self.require_user()?.id;
let setting = db_or_debug_and_return!( let setting = db_or_debug_and_return!(
self, self,
database_actor::user_settings::UpdateUserSetting { database_actor::user_settings::UpdateUserSetting {
user_id, user_id,
mode: msg.mode mode: msg.mode
} }; async
); );
Ok(Some(WsMsg::UserSettingUpdated(setting))) Ok(Some(WsMsg::UserSettingUpdated(setting)))
} }

View File

@ -1,20 +1,21 @@
use database_actor::users::Register as DbRegister; use database_actor::users::Register as DbRegister;
use database_actor::{self}; use database_actor::{self};
use futures::executor::block_on; use jirs_data::msg::{WsMsgInvitation, WsMsgProject};
use jirs_data::{UserId, UserProject, UserRole, WsMsg}; use jirs_data::{UserId, UserProject, UserRole, WsMsg};
use crate::handlers::auth::Authenticate; use crate::handlers::auth::Authenticate;
use crate::{db_or_debug_and_return, WebSocketActor, WsHandler, WsResult}; use crate::{db_or_debug_and_return, AsyncHandler, WebSocketActor, WsResult};
pub struct LoadProjectUsers; pub struct LoadProjectUsers;
impl WsHandler<LoadProjectUsers> for WebSocketActor { #[async_trait::async_trait]
fn handle_msg(&mut self, _msg: LoadProjectUsers, _ctx: &mut Self::Context) -> WsResult { impl AsyncHandler<LoadProjectUsers> for WebSocketActor {
async fn exec(&mut self, _msg: LoadProjectUsers) -> WsResult {
use database_actor::users::LoadProjectUsers as Msg; use database_actor::users::LoadProjectUsers as Msg;
let project_id = self.require_user_project()?.project_id; let project_id = self.require_user_project()?.project_id;
let v = db_or_debug_and_return!(self, Msg { project_id }); let v = db_or_debug_and_return!(self, Msg { project_id }; async);
Ok(Some(WsMsg::ProjectUsersLoaded(v))) Ok(Some(WsMsg::Project(WsMsgProject::ProjectUsersLoaded(v))))
} }
} }
@ -23,8 +24,9 @@ pub struct Register {
pub email: String, pub email: String,
} }
impl WsHandler<Register> for WebSocketActor { #[async_trait::async_trait]
fn handle_msg(&mut self, msg: Register, ctx: &mut Self::Context) -> WsResult { impl AsyncHandler<Register> for WebSocketActor {
async fn exec(&mut self, msg: Register) -> WsResult {
let Register { name, email } = msg; let Register { name, email } = msg;
let _ = db_or_debug_and_return!( let _ = db_or_debug_and_return!(
self, self,
@ -35,10 +37,10 @@ impl WsHandler<Register> for WebSocketActor {
role: UserRole::Owner, role: UserRole::Owner,
}, },
Ok(Some(WsMsg::SignUpPairTaken)), Ok(Some(WsMsg::SignUpPairTaken)),
Ok(None) Ok(None); async
); );
match self.handle_msg(Authenticate { name, email }, ctx) { match self.exec(Authenticate { name, email }).await {
Ok(_) => (), Ok(_) => (),
Err(e) => return Ok(Some(e)), Err(e) => return Ok(Some(e)),
}; };
@ -49,14 +51,16 @@ impl WsHandler<Register> for WebSocketActor {
pub struct LoadInvitedUsers; pub struct LoadInvitedUsers;
impl WsHandler<LoadInvitedUsers> for WebSocketActor { #[async_trait::async_trait]
fn handle_msg(&mut self, _msg: LoadInvitedUsers, _ctx: &mut Self::Context) -> WsResult { impl AsyncHandler<LoadInvitedUsers> for WebSocketActor {
async fn exec(&mut self, _msg: LoadInvitedUsers) -> WsResult {
let user_id = self.require_user()?.id; let user_id = self.require_user()?.id;
let users = let users = db_or_debug_and_return!(self, database_actor::users::LoadInvitedUsers { user_id }; async);
db_or_debug_and_return!(self, database_actor::users::LoadInvitedUsers { user_id });
Ok(Some(WsMsg::InvitedUsersLoaded(users))) Ok(Some(WsMsg::Invitation(
WsMsgInvitation::InvitedUsersLoaded(users),
)))
} }
} }
@ -65,8 +69,9 @@ pub struct ProfileUpdate {
pub email: String, pub email: String,
} }
impl WsHandler<ProfileUpdate> for WebSocketActor { #[async_trait::async_trait]
fn handle_msg(&mut self, msg: ProfileUpdate, _ctx: &mut Self::Context) -> WsResult { impl AsyncHandler<ProfileUpdate> for WebSocketActor {
async fn exec(&mut self, msg: ProfileUpdate) -> WsResult {
let user_id = self.require_user()?.id; let user_id = self.require_user()?.id;
let ProfileUpdate { name, email } = msg; let ProfileUpdate { name, email } = msg;
@ -76,7 +81,7 @@ impl WsHandler<ProfileUpdate> for WebSocketActor {
user_id, user_id,
name, name,
email, email,
} }; async
); );
Ok(Some(WsMsg::ProfileUpdated)) Ok(Some(WsMsg::ProfileUpdated))
@ -87,8 +92,9 @@ pub struct RemoveInvitedUser {
pub user_id: UserId, pub user_id: UserId,
} }
impl WsHandler<RemoveInvitedUser> for WebSocketActor { #[async_trait::async_trait]
fn handle_msg(&mut self, msg: RemoveInvitedUser, _ctx: &mut Self::Context) -> WsResult { impl AsyncHandler<RemoveInvitedUser> for WebSocketActor {
async fn exec(&mut self, msg: RemoveInvitedUser) -> WsResult {
let RemoveInvitedUser { let RemoveInvitedUser {
user_id: invited_id, user_id: invited_id,
} = msg; } = msg;
@ -103,8 +109,10 @@ impl WsHandler<RemoveInvitedUser> for WebSocketActor {
invited_id, invited_id,
inviter_id, inviter_id,
project_id, project_id,
} }; async
); );
Ok(Some(WsMsg::InvitedUserRemoveSuccess(invited_id))) Ok(Some(WsMsg::Invitation(
WsMsgInvitation::InvitedUserRemoveSuccess(invited_id),
)))
} }
} }

View File

@ -7,7 +7,8 @@ use common::{actix_web, actix_web_actors};
use database_actor::projects::LoadCurrentProject; use database_actor::projects::LoadCurrentProject;
use database_actor::user_projects::CurrentUserProject; use database_actor::user_projects::CurrentUserProject;
use database_actor::DbExecutor; use database_actor::DbExecutor;
use futures::executor::block_on; use futures::executor::block_on as wait;
use jirs_data::msg::WsMsgInvitation;
use jirs_data::{Project, User, UserProject, WsMsg}; use jirs_data::{Project, User, UserProject, WsMsg};
use mail_actor::MailExecutor; use mail_actor::MailExecutor;
@ -80,154 +81,65 @@ impl WebSocketActor {
debug!("incoming message: {:?}", msg); debug!("incoming message: {:?}", msg);
} }
let msg = match msg { match msg {
WsMsg::Ping => Some(WsMsg::Pong), WsMsg::Ping => return Ok(Some(WsMsg::Pong)),
WsMsg::Pong => Some(WsMsg::Ping), WsMsg::Pong => return Ok(Some(WsMsg::Ping)),
WsMsg::AuthorizeLoad(uuid) => {
// issues return Ok(self.handle_msg(CheckAuthToken { token: uuid }, ctx)?)
WsMsg::IssueUpdate(id, field_id, payload) => self.handle_msg(
UpdateIssueHandler {
id,
field_id,
payload,
},
ctx,
)?,
WsMsg::IssueCreate(payload) => self.handle_msg(payload, ctx)?,
WsMsg::IssueDelete(id) => self.handle_msg(DeleteIssue { id }, ctx)?,
WsMsg::IssueSyncListPosition(sync) => {
self.handle_msg(SyncIssueListPosition(sync), ctx)?
} }
WsMsg::ProjectIssuesLoad => self.handle_msg(LoadIssues, ctx)?, WsMsg::Invitation(WsMsgInvitation::InvitationAcceptRequest(invitation_token)) => {
return Ok(self.handle_msg(AcceptInvitation { invitation_token }, ctx)?)
// issue statuses
WsMsg::IssueStatusesLoad => self.handle_msg(LoadIssueStatuses, ctx)?,
WsMsg::IssueStatusDelete(issue_status_id) => {
self.handle_msg(DeleteIssueStatus { issue_status_id }, ctx)?
}
WsMsg::IssueStatusUpdate(issue_status_id, name, position) => self.handle_msg(
UpdateIssueStatus {
issue_status_id,
position,
name,
},
ctx,
)?,
WsMsg::IssueStatusCreate(name, position) => {
self.handle_msg(CreateIssueStatus { position, name }, ctx)?
} }
_ => {}
};
// projects let fut = match msg {
WsMsg::ProjectsLoad => self.handle_msg(LoadProjects, ctx)?, WsMsg::Project(m) => self.exec(m),
WsMsg::ProjectUpdateLoad(payload) => self.handle_msg(payload, ctx)?, WsMsg::Issue(m) => self.exec(m),
WsMsg::IssueStatus(m) => self.exec(m),
WsMsg::Comment(m) => self.exec(m),
WsMsg::Invitation(m) => self.exec(m),
WsMsg::Epic(m) => self.exec(m),
// user projects // user projects
WsMsg::UserProjectsLoad => self.handle_msg(LoadUserProjects, ctx)?, WsMsg::UserProjectsLoad => self.exec(LoadUserProjects),
WsMsg::UserProjectSetCurrent(user_project_id) => self.handle_msg( WsMsg::UserProjectSetCurrent(user_project_id) => self.exec(SetCurrentUserProject {
SetCurrentUserProject { id: user_project_id,
id: user_project_id, }),
},
ctx,
)?,
// auth // auth
WsMsg::AuthorizeLoad(uuid) => self.handle_msg(CheckAuthToken { token: uuid }, ctx)?, WsMsg::BindTokenCheck(uuid) => self.exec(CheckBindToken { bind_token: uuid }),
WsMsg::BindTokenCheck(uuid) => { WsMsg::AuthenticateRequest(email, name) => self.exec(Authenticate { name, email }),
self.handle_msg(CheckBindToken { bind_token: uuid }, ctx)?
}
WsMsg::AuthenticateRequest(email, name) => {
self.handle_msg(Authenticate { name, email }, ctx)?
}
// register // register
WsMsg::SignUpRequest(email, username) => self.handle_msg( WsMsg::SignUpRequest(email, username) => self.exec(Register {
Register { name: username,
name: username, email,
email, }),
},
ctx,
)?,
// users
WsMsg::ProjectUsersLoad => self.handle_msg(LoadProjectUsers, ctx)?,
WsMsg::InvitedUserRemoveRequest(user_id) => {
self.handle_msg(RemoveInvitedUser { user_id }, ctx)?
}
// user settings // user settings
WsMsg::UserSettingSetEditorMode(mode) => { WsMsg::UserSettingSetEditorMode(mode) => {
self.handle_msg(user_settings::SetTextEditorMode { mode }, ctx)? self.exec(user_settings::SetTextEditorMode { mode })
} }
// comments
WsMsg::IssueCommentsLoad(issue_id) => {
self.handle_msg(LoadIssueComments { issue_id }, ctx)?
}
WsMsg::CommentCreate(payload) => self.handle_msg(payload, ctx)?,
WsMsg::CommentUpdate(payload) => self.handle_msg(payload, ctx)?,
WsMsg::CommentDelete(comment_id) => {
self.handle_msg(DeleteComment { comment_id }, ctx)?
}
// invitations
WsMsg::InvitationSendRequest { name, email, role } => {
self.handle_msg(CreateInvitation { email, name, role }, ctx)?
}
WsMsg::InvitationListLoad => self.handle_msg(ListInvitation, ctx)?,
WsMsg::InvitationAcceptRequest(invitation_token) => {
self.handle_msg(AcceptInvitation { invitation_token }, ctx)?
}
WsMsg::InvitationRevokeRequest(id) => self.handle_msg(RevokeInvitation { id }, ctx)?,
WsMsg::InvitedUsersLoad => self.handle_msg(LoadInvitedUsers, ctx)?,
// users // users
WsMsg::ProfileUpdate(email, name) => { WsMsg::ProfileUpdate(email, name) => self.exec(ProfileUpdate { name, email }),
self.handle_msg(ProfileUpdate { name, email }, ctx)?
}
// messages // messages
WsMsg::MessagesLoad => self.handle_msg(LoadMessages, ctx)?, WsMsg::MessagesLoad => self.exec(LoadMessages),
WsMsg::MessageMarkSeen(id) => self.handle_msg(MarkMessageSeen { id }, ctx)?, WsMsg::MessageMarkSeen(id) => self.exec(MarkMessageSeen { id }),
// epics
WsMsg::EpicsLoad => self.handle_msg(epics::LoadEpics, ctx)?,
WsMsg::EpicCreate(name, description, description_html) => self.handle_msg(
epics::CreateEpic {
name,
description,
description_html,
},
ctx,
)?,
WsMsg::EpicUpdateName(epic_id, name) => {
self.handle_msg(epics::UpdateEpicName { epic_id, name }, ctx)?
}
WsMsg::EpicUpdateStartsAt(epic_id, starts_at) => {
self.handle_msg(epics::UpdateEpicStartsAt { epic_id, starts_at }, ctx)?
}
WsMsg::EpicUpdateEndsAt(epic_id, ends_at) => {
self.handle_msg(epics::UpdateEpicEndsAt { epic_id, ends_at }, ctx)?
}
WsMsg::EpicDelete(epic_id) => self.handle_msg(epics::DeleteEpic { epic_id }, ctx)?,
WsMsg::EpicTransform(epic_id, issue_type) => self.handle_msg(
epics::TransformEpic {
epic_id,
issue_type,
},
ctx,
)?,
// hi // hi
WsMsg::HighlightCode(lang, code) => { WsMsg::HighlightCode(lang, code) => self.exec(hi::HighlightCode(lang, code)),
self.handle_msg(hi::HighlightCode(lang, code), ctx)?
}
// else fail // else fail
_ => { _ => {
error!("No handle for {:?} specified", msg); error!("No handle for {:?} specified", msg);
None return Ok(None);
} }
}; };
let msg = wait(fut)?;
if msg.is_some() && msg != Some(WsMsg::Pong) { if msg.is_some() && msg != Some(WsMsg::Pong) {
info!("sending message {:?}", msg); info!("sending message {:?}", msg);
} }
@ -251,8 +163,8 @@ impl WebSocketActor {
.send(InnerMsg::Join(project_id, user.id, addr)) .send(InnerMsg::Join(project_id, user.id, addr))
.await .await
{ {
Err(e) => error!("{}", e), Err(e) => common::log::error!("{:?}", e),
_ => info!(" joined channel"), _ => common::log::info!(" joined channel"),
}; };
} }
@ -268,7 +180,7 @@ impl WebSocketActor {
fn load_user_project(&self) -> Result<UserProject, WsMsg> { fn load_user_project(&self) -> Result<UserProject, WsMsg> {
let user_id = self.require_user()?.id; let user_id = self.require_user()?.id;
match block_on(self.db.send(CurrentUserProject { user_id })) { match wait(self.db.send(CurrentUserProject { user_id })) {
Ok(Ok(user_project)) => Ok(user_project), Ok(Ok(user_project)) => Ok(user_project),
Ok(Err(e)) => { Ok(Err(e)) => {
error!("load_user_project encounter service error {:?}", e); error!("load_user_project encounter service error {:?}", e);
@ -283,14 +195,14 @@ impl WebSocketActor {
fn load_project(&self) -> Result<Project, WsMsg> { fn load_project(&self) -> Result<Project, WsMsg> {
let project_id = self.require_user_project()?.project_id; let project_id = self.require_user_project()?.project_id;
match block_on(self.db.send(LoadCurrentProject { project_id })) { match wait(self.db.send(LoadCurrentProject { project_id })) {
Ok(Ok(project)) => Ok(project), Ok(Ok(project)) => Ok(project),
Ok(Err(e)) => { Ok(Err(e)) => {
error!("{:?}", e); error!("{:?}", e);
Err(WsMsg::AuthorizeExpired) Err(WsMsg::AuthorizeExpired)
} }
Err(e) => { Err(e) => {
error!("{}", e); error!("{:?}", e);
Err(WsMsg::AuthorizeExpired) Err(WsMsg::AuthorizeExpired)
} }
} }
@ -347,6 +259,14 @@ where
fn handle_msg(&mut self, msg: Message, _ctx: &mut <Self as Actor>::Context) -> WsResult; fn handle_msg(&mut self, msg: Message, _ctx: &mut <Self as Actor>::Context) -> WsResult;
} }
#[async_trait::async_trait]
pub trait AsyncHandler<Message>
where
Self: actix::Actor<Context = WsCtx>,
{
async fn exec(&mut self, msg: Message) -> WsResult;
}
#[get("/ws/")] #[get("/ws/")]
pub async fn index( pub async fn index(
req: HttpRequest, req: HttpRequest,

View File

@ -6,6 +6,12 @@ macro_rules! db_or_debug_and_return {
($s: ident, $msg: expr) => { ($s: ident, $msg: expr) => {
$crate::actor_or_debug_and_return!($s, db, $msg) $crate::actor_or_debug_and_return!($s, db, $msg)
}; };
($s: ident, $msg: expr, $actor_err: expr, $mailbox_err: expr; async) => {
$crate::actor_or_debug_and_return!($s, db, $msg, $actor_err, $mailbox_err; async)
};
($s: ident, $msg: expr; async) => {
$crate::actor_or_debug_and_return!($s, db, $msg; async)
};
} }
#[macro_export] #[macro_export]
@ -16,6 +22,12 @@ macro_rules! db_or_debug_or_fallback {
($s: ident, $msg: expr) => { ($s: ident, $msg: expr) => {
$crate::actor_or_debug_and_fallback!($s, db, $msg) $crate::actor_or_debug_and_fallback!($s, db, $msg)
}; };
($s: ident, $msg: expr, $actor_err: expr, $mailbox_err: expr;async) => {
$crate::actor_or_debug_and_fallback!($s, db, $msg, $actor_err, $mailbox_err;async)
};
($s: ident, $msg: expr;async) => {
$crate::actor_or_debug_and_fallback!($s, db, $msg;async)
};
} }
#[macro_export] #[macro_export]
@ -26,6 +38,12 @@ macro_rules! mail_or_debug_and_return {
($s: ident, $msg: expr) => { ($s: ident, $msg: expr) => {
$crate::actor_or_debug_and_return!($s, mail, $msg) $crate::actor_or_debug_and_return!($s, mail, $msg)
}; };
($s: ident, $msg: expr, $actor_err: expr, $mailbox_err: expr; async) => {
$crate::actor_or_debug_and_return!($s, mail, $msg, $actor_err, $mailbox_err; async)
};
($s: ident, $msg: expr; async) => {
$crate::actor_or_debug_and_return!($s, mail, $msg; async)
};
} }
#[macro_export] #[macro_export]
@ -46,6 +64,22 @@ macro_rules! actor_or_debug_and_return {
($s: ident, $actor: ident, $msg: expr) => { ($s: ident, $actor: ident, $msg: expr) => {
crate::actor_or_debug_and_return!($s, $actor, $msg, Ok(None), Ok(None)) crate::actor_or_debug_and_return!($s, $actor, $msg, Ok(None), Ok(None))
}; };
($s: ident, $actor: ident, $msg: expr, $actor_err: expr, $mailbox_err: expr; async) => {
match $s.$actor.send($msg).await {
Ok(Ok(r)) => r,
Ok(Err(e)) => {
common::log::error!("{:?}", e);
return $actor_err;
}
Err(e) => {
common::log::error!("{:?}", e);
return $mailbox_err;
}
}
};
($s: ident, $actor: ident, $msg: expr;async) => {
crate::actor_or_debug_and_return!($s, $actor, $msg, Ok(None), Ok(None); async)
};
} }
#[macro_export] #[macro_export]
@ -63,6 +97,19 @@ macro_rules! actor_or_debug_and_ignore {
} }
} }
}; };
($s: ident, $actor: ident, $msg: expr, $on_success: expr;async) => {
match $s.$actor.send($msg).await {
Ok(Ok(r)) => {
$on_success(r);
}
Ok(Err(e)) => {
common::log::error!("{:?}", e);
}
Err(e) => {
common::log::error!("{:?}", e);
}
}
};
} }
#[macro_export] #[macro_export]
@ -80,4 +127,17 @@ macro_rules! actor_or_debug_and_fallback {
} }
} }
}; };
($s: ident, $actor: ident, $msg: expr, $actor_err: expr, $mailbox_err: expr; async) => {
match $s.$actor.send($msg).await {
Ok(Ok(r)) => r,
Ok(Err(e)) => {
common::log::error!("{:?}", e);
$actor_err
}
Err(e) => {
common::log::error!("{:?}", e);
$mailbox_err
}
}
};
} }

View File

@ -1,3 +1,4 @@
use jirs_data::msg::WsMsgEpic;
use jirs_data::WsMsg; use jirs_data::WsMsg;
use seed::prelude::*; use seed::prelude::*;
@ -12,7 +13,11 @@ pub fn update(msg: &Msg, model: &mut crate::model::Model, orders: &mut impl Orde
match msg { match msg {
Msg::DeleteEpic => { Msg::DeleteEpic => {
send_ws_msg(WsMsg::EpicDelete(modal.epic_id), model.ws.as_ref(), orders); send_ws_msg(
WsMsg::Epic(WsMsgEpic::EpicDelete(modal.epic_id)),
model.ws.as_ref(),
orders,
);
} }
Msg::ResourceChanged(ResourceKind::Epic, OperationKind::SingleRemoved, Some(_)) => { Msg::ResourceChanged(ResourceKind::Epic, OperationKind::SingleRemoved, Some(_)) => {
orders.skip().send_msg(Msg::ModalDropped); orders.skip().send_msg(Msg::ModalDropped);

View File

@ -1,3 +1,4 @@
use jirs_data::msg::WsMsgEpic;
use jirs_data::{EpicFieldId, IssueType, WsMsg}; use jirs_data::{EpicFieldId, IssueType, WsMsg};
use seed::prelude::*; use seed::prelude::*;
@ -35,7 +36,7 @@ pub fn update(msg: &Msg, model: &mut crate::model::Model, orders: &mut impl Orde
Msg::StrInputChanged(FieldId::EditEpic(EpicFieldId::Name), s) => { Msg::StrInputChanged(FieldId::EditEpic(EpicFieldId::Name), s) => {
let epic_id = modal.epic_id; let epic_id = modal.epic_id;
send_ws_msg( send_ws_msg(
WsMsg::EpicUpdateName(epic_id, s.to_string()), WsMsg::Epic(WsMsgEpic::EpicUpdateName(epic_id, s.to_string())),
model.ws.as_ref(), model.ws.as_ref(),
orders, orders,
); );
@ -46,7 +47,7 @@ pub fn update(msg: &Msg, model: &mut crate::model::Model, orders: &mut impl Orde
) => { ) => {
let epic_id = modal.epic_id; let epic_id = modal.epic_id;
send_ws_msg( send_ws_msg(
WsMsg::EpicUpdateStartsAt(epic_id, Some(*date)), WsMsg::Epic(WsMsgEpic::EpicUpdateStartsAt(epic_id, Some(*date))),
model.ws.as_ref(), model.ws.as_ref(),
orders, orders,
); );
@ -57,7 +58,7 @@ pub fn update(msg: &Msg, model: &mut crate::model::Model, orders: &mut impl Orde
) => { ) => {
let epic_id = modal.epic_id; let epic_id = modal.epic_id;
send_ws_msg( send_ws_msg(
WsMsg::EpicUpdateEndsAt(epic_id, Some(*date)), WsMsg::Epic(WsMsgEpic::EpicUpdateEndsAt(epic_id, Some(*date))),
model.ws.as_ref(), model.ws.as_ref(),
orders, orders,
); );
@ -66,7 +67,7 @@ pub fn update(msg: &Msg, model: &mut crate::model::Model, orders: &mut impl Orde
let epic_id = modal.epic_id; let epic_id = modal.epic_id;
let issue_type: IssueType = modal.transform_into.value.into(); let issue_type: IssueType = modal.transform_into.value.into();
send_ws_msg( send_ws_msg(
WsMsg::EpicTransform(epic_id, issue_type), WsMsg::Epic(WsMsgEpic::EpicTransform(epic_id, issue_type)),
model.ws.as_ref(), model.ws.as_ref(),
orders, orders,
); );

View File

@ -1,3 +1,4 @@
use jirs_data::msg::WsMsgIssueStatus;
use jirs_data::WsMsg; use jirs_data::WsMsg;
use seed::prelude::*; use seed::prelude::*;
@ -13,7 +14,7 @@ pub fn update(msg: &Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
match msg { match msg {
Msg::DeleteIssueStatus(issue_status_id) => { Msg::DeleteIssueStatus(issue_status_id) => {
crate::ws::send_ws_msg( crate::ws::send_ws_msg(
WsMsg::IssueStatusDelete(*issue_status_id), WsMsg::IssueStatus(WsMsgIssueStatus::IssueStatusDelete(*issue_status_id)),
model.ws.as_ref(), model.ws.as_ref(),
orders, orders,
); );

View File

@ -1,3 +1,4 @@
use jirs_data::msg::{WsMsgEpic, WsMsgIssue};
use jirs_data::{IssueFieldId, UserId, WsMsg}; use jirs_data::{IssueFieldId, UserId, WsMsg};
use seed::prelude::*; use seed::prelude::*;
@ -24,7 +25,11 @@ pub fn update(msg: &Msg, model: &mut crate::model::Model, orders: &mut impl Orde
} }
Msg::AddEpic => { Msg::AddEpic => {
send_ws_msg( send_ws_msg(
WsMsg::EpicCreate(modal.title_state.value.clone(), None, None), WsMsg::Epic(WsMsgEpic::EpicCreate(
modal.title_state.value.clone(),
None,
None,
)),
model.ws.as_ref(), model.ws.as_ref(),
orders, orders,
); );
@ -51,7 +56,7 @@ pub fn update(msg: &Msg, model: &mut crate::model::Model, orders: &mut impl Orde
}; };
send_ws_msg( send_ws_msg(
jirs_data::WsMsg::IssueCreate(payload), jirs_data::WsMsg::Issue(WsMsgIssue::IssueCreate(payload)),
model.ws.as_ref(), model.ws.as_ref(),
orders, orders,
); );

View File

@ -1,3 +1,4 @@
use jirs_data::msg::{WsMsgComment, WsMsgIssue};
use jirs_data::*; use jirs_data::*;
use seed::prelude::*; use seed::prelude::*;
@ -32,11 +33,11 @@ pub fn update(msg: &Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
) => { ) => {
modal.payload.issue_type = (*value).into(); modal.payload.issue_type = (*value).into();
send_ws_msg( send_ws_msg(
WsMsg::IssueUpdate( WsMsg::Issue(WsMsgIssue::IssueUpdate(
modal.id, modal.id,
IssueFieldId::Type, IssueFieldId::Type,
PayloadVariant::IssueType(modal.payload.issue_type), PayloadVariant::IssueType(modal.payload.issue_type),
), )),
model.ws.as_ref(), model.ws.as_ref(),
orders, orders,
); );
@ -49,11 +50,11 @@ pub fn update(msg: &Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
) => { ) => {
modal.payload.issue_status_id = *value as IssueStatusId; modal.payload.issue_status_id = *value as IssueStatusId;
send_ws_msg( send_ws_msg(
WsMsg::IssueUpdate( WsMsg::Issue(WsMsgIssue::IssueUpdate(
modal.id, modal.id,
IssueFieldId::IssueStatusId, IssueFieldId::IssueStatusId,
PayloadVariant::I32(modal.payload.issue_status_id), PayloadVariant::I32(modal.payload.issue_status_id),
), )),
model.ws.as_ref(), model.ws.as_ref(),
orders, orders,
); );
@ -66,11 +67,11 @@ pub fn update(msg: &Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
) => { ) => {
modal.payload.reporter_id = *value as i32; modal.payload.reporter_id = *value as i32;
send_ws_msg( send_ws_msg(
WsMsg::IssueUpdate( WsMsg::Issue(WsMsgIssue::IssueUpdate(
modal.id, modal.id,
IssueFieldId::Reporter, IssueFieldId::Reporter,
PayloadVariant::I32(modal.payload.reporter_id), PayloadVariant::I32(modal.payload.reporter_id),
), )),
model.ws.as_ref(), model.ws.as_ref(),
orders, orders,
); );
@ -83,11 +84,11 @@ pub fn update(msg: &Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
) => { ) => {
modal.payload.user_ids.push(*value as i32); modal.payload.user_ids.push(*value as i32);
send_ws_msg( send_ws_msg(
WsMsg::IssueUpdate( WsMsg::Issue(WsMsgIssue::IssueUpdate(
modal.id, modal.id,
IssueFieldId::Assignees, IssueFieldId::Assignees,
PayloadVariant::VecI32(modal.payload.user_ids.clone()), PayloadVariant::VecI32(modal.payload.user_ids.clone()),
), )),
model.ws.as_ref(), model.ws.as_ref(),
orders, orders,
); );
@ -104,11 +105,11 @@ pub fn update(msg: &Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
} }
} }
send_ws_msg( send_ws_msg(
WsMsg::IssueUpdate( WsMsg::Issue(WsMsgIssue::IssueUpdate(
modal.id, modal.id,
IssueFieldId::Assignees, IssueFieldId::Assignees,
PayloadVariant::VecI32(modal.payload.user_ids.clone()), PayloadVariant::VecI32(modal.payload.user_ids.clone()),
), )),
model.ws.as_ref(), model.ws.as_ref(),
orders, orders,
); );
@ -121,11 +122,12 @@ pub fn update(msg: &Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
) => { ) => {
modal.payload.priority = (*value).into(); modal.payload.priority = (*value).into();
send_ws_msg( send_ws_msg(
WsMsg::IssueUpdate( WsMsgIssue::IssueUpdate(
modal.id, modal.id,
IssueFieldId::Priority, IssueFieldId::Priority,
PayloadVariant::IssuePriority(modal.payload.priority), PayloadVariant::IssuePriority(modal.payload.priority),
), )
.into(),
model.ws.as_ref(), model.ws.as_ref(),
orders, orders,
); );
@ -138,11 +140,12 @@ pub fn update(msg: &Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
) => { ) => {
modal.payload.title = value.clone(); modal.payload.title = value.clone();
send_ws_msg( send_ws_msg(
WsMsg::IssueUpdate( WsMsgIssue::IssueUpdate(
modal.id, modal.id,
IssueFieldId::Title, IssueFieldId::Title,
PayloadVariant::String(modal.payload.title.clone()), PayloadVariant::String(modal.payload.title.clone()),
), )
.into(),
model.ws.as_ref(), model.ws.as_ref(),
orders, orders,
); );
@ -156,7 +159,7 @@ pub fn update(msg: &Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
) => { ) => {
modal.payload.description_text = Some(value.clone()); modal.payload.description_text = Some(value.clone());
send_ws_msg( send_ws_msg(
WsMsg::IssueUpdate( WsMsgIssue::IssueUpdate(
modal.id, modal.id,
IssueFieldId::Description, IssueFieldId::Description,
PayloadVariant::String( PayloadVariant::String(
@ -167,7 +170,8 @@ pub fn update(msg: &Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
.cloned() .cloned()
.unwrap_or_default(), .unwrap_or_default(),
), ),
), )
.into(),
model.ws.as_ref(), model.ws.as_ref(),
orders, orders,
); );
@ -180,11 +184,12 @@ pub fn update(msg: &Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
) => { ) => {
modal.payload.time_spent = modal.time_spent.represent_f64_as_i32(); modal.payload.time_spent = modal.time_spent.represent_f64_as_i32();
send_ws_msg( send_ws_msg(
WsMsg::IssueUpdate( WsMsgIssue::IssueUpdate(
modal.id, modal.id,
IssueFieldId::TimeSpent, IssueFieldId::TimeSpent,
PayloadVariant::OptionI32(modal.payload.time_spent), PayloadVariant::OptionI32(modal.payload.time_spent),
), )
.into(),
model.ws.as_ref(), model.ws.as_ref(),
orders, orders,
); );
@ -195,11 +200,12 @@ pub fn update(msg: &Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
) => { ) => {
modal.payload.time_spent = modal.time_spent_select.values.get(0).map(|n| *n as i32); modal.payload.time_spent = modal.time_spent_select.values.get(0).map(|n| *n as i32);
send_ws_msg( send_ws_msg(
WsMsg::IssueUpdate( WsMsgIssue::IssueUpdate(
modal.id, modal.id,
IssueFieldId::TimeSpent, IssueFieldId::TimeSpent,
PayloadVariant::OptionI32(modal.payload.time_spent), PayloadVariant::OptionI32(modal.payload.time_spent),
), )
.into(),
model.ws.as_ref(), model.ws.as_ref(),
orders, orders,
); );
@ -211,11 +217,12 @@ pub fn update(msg: &Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
) => { ) => {
modal.payload.time_remaining = modal.time_remaining.represent_f64_as_i32(); modal.payload.time_remaining = modal.time_remaining.represent_f64_as_i32();
send_ws_msg( send_ws_msg(
WsMsg::IssueUpdate( WsMsgIssue::IssueUpdate(
modal.id, modal.id,
IssueFieldId::TimeRemaining, IssueFieldId::TimeRemaining,
PayloadVariant::OptionI32(modal.payload.time_remaining), PayloadVariant::OptionI32(modal.payload.time_remaining),
), )
.into(),
model.ws.as_ref(), model.ws.as_ref(),
orders, orders,
); );
@ -227,11 +234,12 @@ pub fn update(msg: &Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
modal.payload.time_remaining = modal.payload.time_remaining =
modal.time_remaining_select.values.get(0).map(|n| *n as i32); modal.time_remaining_select.values.get(0).map(|n| *n as i32);
send_ws_msg( send_ws_msg(
WsMsg::IssueUpdate( WsMsgIssue::IssueUpdate(
modal.id, modal.id,
IssueFieldId::TimeRemaining, IssueFieldId::TimeRemaining,
PayloadVariant::OptionI32(modal.payload.time_remaining), PayloadVariant::OptionI32(modal.payload.time_remaining),
), )
.into(),
model.ws.as_ref(), model.ws.as_ref(),
orders, orders,
); );
@ -243,11 +251,12 @@ pub fn update(msg: &Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
) => { ) => {
modal.payload.estimate = modal.estimate.represent_f64_as_i32(); modal.payload.estimate = modal.estimate.represent_f64_as_i32();
send_ws_msg( send_ws_msg(
WsMsg::IssueUpdate( WsMsgIssue::IssueUpdate(
modal.id, modal.id,
IssueFieldId::Estimate, IssueFieldId::Estimate,
PayloadVariant::OptionI32(modal.payload.estimate), PayloadVariant::OptionI32(modal.payload.estimate),
), )
.into(),
model.ws.as_ref(), model.ws.as_ref(),
orders, orders,
); );
@ -258,11 +267,12 @@ pub fn update(msg: &Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
) => { ) => {
modal.payload.estimate = modal.estimate_select.values.get(0).map(|n| *n as i32); modal.payload.estimate = modal.estimate_select.values.get(0).map(|n| *n as i32);
send_ws_msg( send_ws_msg(
WsMsg::IssueUpdate( WsMsgIssue::IssueUpdate(
modal.id, modal.id,
IssueFieldId::Estimate, IssueFieldId::Estimate,
PayloadVariant::OptionI32(modal.payload.estimate), PayloadVariant::OptionI32(modal.payload.estimate),
), )
.into(),
model.ws.as_ref(), model.ws.as_ref(),
orders, orders,
); );
@ -272,11 +282,12 @@ pub fn update(msg: &Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
StyledSelectChanged::Changed(v), StyledSelectChanged::Changed(v),
) => { ) => {
send_ws_msg( send_ws_msg(
WsMsg::IssueUpdate( WsMsgIssue::IssueUpdate(
modal.id, modal.id,
IssueFieldId::EpicName, IssueFieldId::EpicName,
PayloadVariant::OptionI32(v.map(|n| n as EpicId)), PayloadVariant::OptionI32(v.map(|n| n as EpicId)),
), )
.into(),
model.ws.as_ref(), model.ws.as_ref(),
orders, orders,
); );
@ -301,17 +312,17 @@ pub fn update(msg: &Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
} }
Msg::SaveComment => { Msg::SaveComment => {
let msg = match modal.comment_form.id { let msg = match modal.comment_form.id {
Some(id) => WsMsg::CommentUpdate(UpdateCommentPayload { Some(id) => WsMsgComment::CommentUpdate(UpdateCommentPayload {
id, id,
body: modal.comment_form.body.clone(), body: modal.comment_form.body.clone(),
}), }),
_ => WsMsg::CommentCreate(CreateCommentPayload { _ => WsMsgComment::CommentCreate(CreateCommentPayload {
user_id: None, user_id: None,
body: modal.comment_form.body.clone(), body: modal.comment_form.body.clone(),
issue_id: modal.id, issue_id: modal.id,
}), }),
}; };
send_ws_msg(msg, model.ws.as_ref(), orders); send_ws_msg(msg.into(), model.ws.as_ref(), orders);
orders orders
.skip() .skip()
.send_msg(Msg::ModalChanged(FieldChange::ToggleCommentForm( .send_msg(Msg::ModalChanged(FieldChange::ToggleCommentForm(
@ -335,7 +346,11 @@ pub fn update(msg: &Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
modal.comment_form.creating = true; modal.comment_form.creating = true;
} }
Msg::DeleteComment(comment_id) => { Msg::DeleteComment(comment_id) => {
send_ws_msg(WsMsg::CommentDelete(*comment_id), model.ws.as_ref(), orders); send_ws_msg(
WsMsgComment::CommentDelete(*comment_id).into(),
model.ws.as_ref(),
orders,
);
orders.skip().send_msg(Msg::ModalDropped); orders.skip().send_msg(Msg::ModalDropped);
} }

View File

@ -1,3 +1,4 @@
use jirs_data::msg::WsMsgComment;
use jirs_data::{CommentId, EpicId, IssueId, IssueStatusId, TimeTracking, WsMsg}; use jirs_data::{CommentId, EpicId, IssueId, IssueStatusId, TimeTracking, WsMsg};
use seed::prelude::*; use seed::prelude::*;
@ -193,7 +194,7 @@ fn push_edit_issue_modal(issue_id: EpicId, model: &mut Model, orders: &mut impl
crate::modals::issues_edit::Model::new(user_mode, issue, time_tracking_type) crate::modals::issues_edit::Model::new(user_mode, issue, time_tracking_type)
}; };
send_ws_msg( send_ws_msg(
WsMsg::IssueCommentsLoad(issue_id), WsMsg::Comment(WsMsgComment::IssueCommentsLoad(issue_id)),
model.ws.as_ref(), model.ws.as_ref(),
orders, orders,
); );

View File

@ -1,4 +1,4 @@
use jirs_data::WsMsg; use jirs_data::msg::WsMsgIssueStatus;
use seed::app::Orders; use seed::app::Orders;
use crate::model::{Model, Page, PageContent}; use crate::model::{Model, Page, PageContent};
@ -39,5 +39,9 @@ fn build_page_content(model: &mut Model, orders: &mut impl Orders<Msg>) {
return; return;
} }
model.page_content = PageContent::Epics(Box::new(super::EpicsPage::new(model))); model.page_content = PageContent::Epics(Box::new(super::EpicsPage::new(model)));
send_ws_msg(WsMsg::IssueStatusesLoad, model.ws.as_ref(), orders); send_ws_msg(
WsMsgIssueStatus::IssueStatusesLoad.into(),
model.ws.as_ref(),
orders,
);
} }

View File

@ -1,6 +1,7 @@
use std::str::FromStr; use std::str::FromStr;
use jirs_data::fields::*; use jirs_data::fields::*;
use jirs_data::msg::WsMsgInvitation;
use jirs_data::WsMsg; use jirs_data::WsMsg;
use seed::prelude::*; use seed::prelude::*;
@ -26,10 +27,10 @@ pub fn update(msg: Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
match msg { match msg {
Msg::WebSocketChange(WebSocketChanged::WsMsg(ws_msg)) => match ws_msg { Msg::WebSocketChange(WebSocketChanged::WsMsg(ws_msg)) => match ws_msg {
WsMsg::InvitationAcceptFailure(_) => { WsMsg::Invitation(WsMsgInvitation::InvitationAcceptFailure(_)) => {
page.error = Some("Invalid token".to_string()); page.error = Some("Invalid token".to_string());
} }
WsMsg::InvitationAcceptSuccess(token) => { WsMsg::Invitation(WsMsgInvitation::InvitationAcceptSuccess(token)) => {
if let Ok(Msg::AuthTokenStored) = write_auth_token(Some(token)) { if let Ok(Msg::AuthTokenStored) = write_auth_token(Some(token)) {
authorize_or_redirect(model, orders); authorize_or_redirect(model, orders);
} }
@ -44,7 +45,7 @@ pub fn update(msg: Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
Msg::PageChanged(PageChanged::Invitation(InvitationPageChange::SubmitForm)) => { Msg::PageChanged(PageChanged::Invitation(InvitationPageChange::SubmitForm)) => {
if let Ok(token) = uuid::Uuid::from_str(page.token.as_str()) { if let Ok(token) = uuid::Uuid::from_str(page.token.as_str()) {
send_ws_msg( send_ws_msg(
WsMsg::InvitationAcceptRequest(token), WsMsgInvitation::InvitationAcceptRequest(token).into(),
model.ws.as_ref(), model.ws.as_ref(),
orders, orders,
); );

View File

@ -1,3 +1,4 @@
use jirs_data::msg::WsMsgIssue;
use jirs_data::*; use jirs_data::*;
use seed::prelude::Orders; use seed::prelude::Orders;
@ -106,7 +107,7 @@ pub fn update(msg: Msg, model: &mut crate::model::Model, orders: &mut impl Order
} }
Msg::DeleteIssue(issue_id) => { Msg::DeleteIssue(issue_id) => {
send_ws_msg( send_ws_msg(
jirs_data::WsMsg::IssueDelete(issue_id), jirs_data::WsMsg::Issue(WsMsgIssue::IssueDelete(issue_id)),
model.ws.as_ref(), model.ws.as_ref(),
orders, orders,
); );

View File

@ -1,5 +1,6 @@
use std::collections::HashSet; use std::collections::HashSet;
use jirs_data::msg::{WsMsgIssueStatus, WsMsgProject};
use jirs_data::{IssueStatus, IssueStatusId, ProjectFieldId, UpdateProjectPayload, WsMsg}; use jirs_data::{IssueStatus, IssueStatusId, ProjectFieldId, UpdateProjectPayload, WsMsg};
use seed::prelude::Orders; use seed::prelude::Orders;
@ -22,7 +23,9 @@ pub fn update(msg: Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
WebSocketChanged::WsMsg(WsMsg::AuthorizeLoaded(..)) => { WebSocketChanged::WsMsg(WsMsg::AuthorizeLoaded(..)) => {
board_load(model, orders); board_load(model, orders);
} }
WebSocketChanged::WsMsg(WsMsg::IssueStatusCreated(_)) => { WebSocketChanged::WsMsg(WsMsg::IssueStatus(WsMsgIssueStatus::IssueStatusCreated(
_,
))) => {
match &mut model.page_content { match &mut model.page_content {
PageContent::ProjectSettings(page) if Some(0) == page.edit_column_id => { PageContent::ProjectSettings(page) if Some(0) == page.edit_column_id => {
page.reset(); page.reset();
@ -83,14 +86,15 @@ pub fn update(msg: Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
ProjectPageChange::SubmitProjectSettingsForm, ProjectPageChange::SubmitProjectSettingsForm,
)) => { )) => {
send_ws_msg( send_ws_msg(
WsMsg::ProjectUpdateLoad(UpdateProjectPayload { WsMsgProject::ProjectUpdateLoad(UpdateProjectPayload {
id: page.payload.id, id: page.payload.id,
name: page.payload.name.clone(), name: page.payload.name.clone(),
url: page.payload.url.clone(), url: page.payload.url.clone(),
description: page.payload.description.clone(), description: page.payload.description.clone(),
category: page.payload.category, category: page.payload.category,
time_tracking: Some(page.time_tracking.value.into()), time_tracking: Some(page.time_tracking.value.into()),
}), })
.into(),
model.ws.as_ref(), model.ws.as_ref(),
orders, orders,
); );
@ -129,7 +133,7 @@ pub fn update(msg: Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
.map(|is| (is.id, is.position)) .map(|is| (is.id, is.position))
{ {
send_ws_msg( send_ws_msg(
WsMsg::IssueStatusUpdate(id, name, pos), WsMsgIssueStatus::IssueStatusUpdate(id, name, pos).into(),
model.ws.as_ref(), model.ws.as_ref(),
orders, orders,
); );
@ -153,7 +157,7 @@ pub fn update(msg: Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
)) => { )) => {
let name = page.name.value.clone(); let name = page.name.value.clone();
let position = model.issue_statuses.len(); let position = model.issue_statuses.len();
let ws_msg = WsMsg::IssueStatusCreate(name, position as i32); let ws_msg = WsMsgIssueStatus::IssueStatusCreate(name, position as i32).into();
send_ws_msg(ws_msg, model.ws.as_ref(), orders); send_ws_msg(ws_msg, model.ws.as_ref(), orders);
} }
_ => (), _ => (),
@ -226,7 +230,7 @@ fn sync(model: &mut Model, orders: &mut impl Orders<Msg>) {
_ => continue, _ => continue,
}; };
send_ws_msg( send_ws_msg(
WsMsg::IssueStatusUpdate(id, name.clone(), *position), WsMsgIssueStatus::IssueStatusUpdate(id, name.clone(), *position).into(),
model.ws.as_ref(), model.ws.as_ref(),
orders, orders,
); );
@ -247,5 +251,9 @@ fn build_page_content(model: &mut Model, orders: &mut impl Orders<Msg>) {
PageContent::ProjectSettings(Box::new(ProjectSettingsPage::new(mode, project))); PageContent::ProjectSettings(Box::new(ProjectSettingsPage::new(mode, project)));
} }
send_ws_msg(WsMsg::IssueStatusesLoad, model.ws.as_ref(), orders); send_ws_msg(
WsMsgIssueStatus::IssueStatusesLoad.into(),
model.ws.as_ref(),
orders,
);
} }

View File

@ -1,3 +1,4 @@
use jirs_data::msg::WsMsgInvitation;
use jirs_data::{InvitationState, UserRole, UsersFieldId, WsMsg}; use jirs_data::{InvitationState, UserRole, UsersFieldId, WsMsg};
use seed::prelude::Orders; use seed::prelude::Orders;
@ -28,13 +29,19 @@ pub fn update(msg: Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
WebSocketChanged::WsMsg(WsMsg::AuthorizeLoaded(Ok(_))) if model.user.is_some() => { WebSocketChanged::WsMsg(WsMsg::AuthorizeLoaded(Ok(_))) if model.user.is_some() => {
invitation_load(model, orders); invitation_load(model, orders);
} }
WebSocketChanged::WsMsg(WsMsg::InvitedUsersLoaded(users)) => { WebSocketChanged::WsMsg(WsMsg::Invitation(WsMsgInvitation::InvitedUsersLoaded(
users,
))) => {
page.invited_users = users; page.invited_users = users;
} }
WebSocketChanged::WsMsg(WsMsg::InvitationListLoaded(invitations)) => { WebSocketChanged::WsMsg(WsMsg::Invitation(WsMsgInvitation::InvitationListLoaded(
invitations,
))) => {
page.invitations = invitations; page.invitations = invitations;
} }
WebSocketChanged::WsMsg(WsMsg::InvitationRevokeSuccess(id)) => { WebSocketChanged::WsMsg(WsMsg::Invitation(
WsMsgInvitation::InvitationRevokeSuccess(id),
)) => {
let mut old = vec![]; let mut old = vec![];
std::mem::swap(&mut page.invitations, &mut old); std::mem::swap(&mut page.invitations, &mut old);
for mut invitation in old { for mut invitation in old {
@ -43,9 +50,15 @@ pub fn update(msg: Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
} }
page.invitations.push(invitation); page.invitations.push(invitation);
} }
send_ws_msg(WsMsg::InvitationListLoad, model.ws.as_ref(), orders); send_ws_msg(
WsMsgInvitation::InvitationListLoad.into(),
model.ws.as_ref(),
orders,
);
} }
WebSocketChanged::WsMsg(WsMsg::InvitedUserRemoveSuccess(removed_id)) => { WebSocketChanged::WsMsg(WsMsg::Invitation(
WsMsgInvitation::InvitedUserRemoveSuccess(removed_id),
)) => {
let mut old = vec![]; let mut old = vec![];
std::mem::swap(&mut page.invited_users, &mut old); std::mem::swap(&mut page.invited_users, &mut old);
for user in old { for user in old {
@ -54,11 +67,15 @@ pub fn update(msg: Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
} }
} }
} }
WebSocketChanged::WsMsg(WsMsg::InvitationSendSuccess) => { WebSocketChanged::WsMsg(WsMsg::Invitation(WsMsgInvitation::InvitationSendSuccess)) => {
send_ws_msg(WsMsg::InvitationListLoad, model.ws.as_ref(), orders); send_ws_msg(
WsMsgInvitation::InvitationListLoad.into(),
model.ws.as_ref(),
orders,
);
page.form_state = InvitationFormState::Succeed; page.form_state = InvitationFormState::Succeed;
} }
WebSocketChanged::WsMsg(WsMsg::InvitationSendFailure) => { WebSocketChanged::WsMsg(WsMsg::Invitation(WsMsgInvitation::InvitationSendFailure)) => {
page.form_state = InvitationFormState::Failed; page.form_state = InvitationFormState::Failed;
} }
_ => (), _ => (),
@ -94,25 +111,25 @@ pub fn update(msg: Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
page.form_state = InvitationFormState::Sent; page.form_state = InvitationFormState::Sent;
send_ws_msg( send_ws_msg(
WsMsg::InvitationSendRequest { WsMsg::Invitation(WsMsgInvitation::InvitationSendRequest {
name: page.name.clone(), name: page.name.clone(),
email: page.email.clone(), email: page.email.clone(),
role, role,
}, }),
model.ws.as_ref(), model.ws.as_ref(),
orders, orders,
); );
} }
Msg::InviteRevokeRequest(invitation_id) => { Msg::InviteRevokeRequest(invitation_id) => {
send_ws_msg( send_ws_msg(
WsMsg::InvitationRevokeRequest(invitation_id), WsMsg::Invitation(WsMsgInvitation::InvitationRevokeRequest(invitation_id)),
model.ws.as_ref(), model.ws.as_ref(),
orders, orders,
); );
} }
Msg::InvitedUserRemove(user_id) => { Msg::InvitedUserRemove(user_id) => {
send_ws_msg( send_ws_msg(
WsMsg::InvitedUserRemoveRequest(user_id), WsMsg::Invitation(WsMsgInvitation::InvitedUserRemoveRequest(user_id)),
model.ws.as_ref(), model.ws.as_ref(),
orders, orders,
); );

View File

@ -1,3 +1,4 @@
use jirs_data::msg::WsMsgProject;
use jirs_data::{UserRole, WsMsg}; use jirs_data::{UserRole, WsMsg};
use seed::prelude::*; use seed::prelude::*;
use seed::*; use seed::*;
@ -13,8 +14,8 @@ pub fn update(msg: &Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
enqueue_ws_msg( enqueue_ws_msg(
vec![ vec![
WsMsg::UserProjectsLoad, WsMsg::UserProjectsLoad,
WsMsg::ProjectsLoad, WsMsg::Project(WsMsgProject::ProjectsLoad),
WsMsg::ProjectUsersLoad, WsMsg::Project(WsMsgProject::ProjectUsersLoad),
WsMsg::MessagesLoad, WsMsg::MessagesLoad,
], ],
model.ws.as_ref(), model.ws.as_ref(),

View File

@ -1,3 +1,4 @@
use jirs_data::msg::WsMsgInvitation;
use jirs_data::{InvitationToken, Message, MessageType, WsMsg}; use jirs_data::{InvitationToken, Message, MessageType, WsMsg};
use seed::prelude::*; use seed::prelude::*;
use seed::*; use seed::*;
@ -35,8 +36,12 @@ impl IntoNavItemIcon for Icon {
pub fn update(msg: &Msg, model: &mut Model, orders: &mut impl Orders<Msg>) { pub fn update(msg: &Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
let m = match msg { let m = match msg {
Msg::MessageInvitationApproved(token) => WsMsg::InvitationAcceptRequest(*token), Msg::MessageInvitationApproved(token) => {
Msg::MessageInvitationDismiss(token) => WsMsg::InvitationRejectRequest(*token), WsMsgInvitation::InvitationAcceptRequest(*token).into()
}
Msg::MessageInvitationDismiss(token) => {
WsMsgInvitation::InvitationRejectRequest(*token).into()
}
Msg::MessageSeen(id) => WsMsg::MessageMarkSeen(*id), Msg::MessageSeen(id) => WsMsg::MessageMarkSeen(*id),
_ => return, _ => return,
}; };

View File

@ -1,3 +1,4 @@
use jirs_data::msg::{WsMsgEpic, WsMsgInvitation, WsMsgIssueStatus, WsMsgProject};
use jirs_data::WsMsg; use jirs_data::WsMsg;
use seed::app::Orders; use seed::app::Orders;
@ -8,10 +9,10 @@ use crate::Msg;
pub fn board_load(model: &mut Model, orders: &mut impl Orders<Msg>) { pub fn board_load(model: &mut Model, orders: &mut impl Orders<Msg>) {
enqueue_ws_msg( enqueue_ws_msg(
vec![ vec![
WsMsg::IssueStatusesLoad, WsMsg::IssueStatus(WsMsgIssueStatus::IssueStatusesLoad),
WsMsg::ProjectIssuesLoad, WsMsg::Project(WsMsgProject::ProjectIssuesLoad),
WsMsg::ProjectUsersLoad, WsMsg::Project(WsMsgProject::ProjectUsersLoad),
WsMsg::EpicsLoad, WsMsg::Epic(WsMsgEpic::EpicsLoad),
], ],
model.ws.as_ref(), model.ws.as_ref(),
orders, orders,
@ -20,7 +21,10 @@ pub fn board_load(model: &mut Model, orders: &mut impl Orders<Msg>) {
pub fn invitation_load(model: &mut Model, orders: &mut impl Orders<Msg>) { pub fn invitation_load(model: &mut Model, orders: &mut impl Orders<Msg>) {
enqueue_ws_msg( enqueue_ws_msg(
vec![WsMsg::InvitationListLoad, WsMsg::InvitedUsersLoad], vec![
WsMsg::Invitation(WsMsgInvitation::InvitationListLoad),
WsMsg::Invitation(WsMsgInvitation::InvitedUsersLoad),
],
model.ws.as_ref(), model.ws.as_ref(),
orders, orders,
); );

View File

@ -1,3 +1,4 @@
use jirs_data::msg::WsMsgIssue;
use jirs_data::*; use jirs_data::*;
use seed::prelude::Orders; use seed::prelude::Orders;
use seed::*; use seed::*;
@ -104,7 +105,7 @@ pub fn sync(model: &mut Model, orders: &mut impl Orders<Msg>) {
.collect(); .collect();
send_ws_msg( send_ws_msg(
WsMsg::IssueSyncListPosition(changes), WsMsg::Issue(WsMsgIssue::IssueSyncListPosition(changes)),
model.ws.as_ref(), model.ws.as_ref(),
orders, orders,
); );

View File

@ -1,4 +1,5 @@
pub use init_load_sets::*; pub use init_load_sets::*;
use jirs_data::msg::{WsMsgComment, WsMsgEpic, WsMsgIssue, WsMsgIssueStatus, WsMsgProject};
use jirs_data::*; use jirs_data::*;
use seed::prelude::*; use seed::prelude::*;
@ -129,7 +130,7 @@ pub fn update(msg: WsMsg, model: &mut Model, orders: &mut impl Orders<Msg>) {
} }
} }
// project // project
WsMsg::ProjectsLoaded(v) => { WsMsg::Project(WsMsgProject::ProjectsLoaded(v)) => {
model.projects = v; model.projects = v;
init_current_project(model, orders); init_current_project(model, orders);
orders.send_msg(Msg::ResourceChanged( orders.send_msg(Msg::ResourceChanged(
@ -175,7 +176,7 @@ pub fn update(msg: WsMsg, model: &mut Model, orders: &mut impl Orders<Msg>) {
} }
// issue statuses // issue statuses
WsMsg::IssueStatusesLoaded(v) => { WsMsg::IssueStatus(WsMsgIssueStatus::IssueStatusesLoaded(v)) => {
model.issue_statuses = v; model.issue_statuses = v;
model model
.issue_statuses .issue_statuses
@ -186,7 +187,7 @@ pub fn update(msg: WsMsg, model: &mut Model, orders: &mut impl Orders<Msg>) {
None, None,
)); ));
} }
WsMsg::IssueStatusCreated(is) => { WsMsg::IssueStatus(WsMsgIssueStatus::IssueStatusCreated(is)) => {
let id = is.id; let id = is.id;
model.issue_statuses.push(is); model.issue_statuses.push(is);
model model
@ -198,7 +199,7 @@ pub fn update(msg: WsMsg, model: &mut Model, orders: &mut impl Orders<Msg>) {
Some(id), Some(id),
)); ));
} }
WsMsg::IssueStatusUpdated(mut changed) => { WsMsg::IssueStatus(WsMsgIssueStatus::IssueStatusUpdated(mut changed)) => {
let id = changed.id; let id = changed.id;
if let Some(idx) = model.issue_statuses.iter().position(|c| c.id == changed.id) { if let Some(idx) = model.issue_statuses.iter().position(|c| c.id == changed.id) {
std::mem::swap(&mut model.issue_statuses[idx], &mut changed); std::mem::swap(&mut model.issue_statuses[idx], &mut changed);
@ -212,7 +213,7 @@ pub fn update(msg: WsMsg, model: &mut Model, orders: &mut impl Orders<Msg>) {
Some(id), Some(id),
)); ));
} }
WsMsg::IssueStatusDeleted(dropped_id, _count) => { WsMsg::IssueStatus(WsMsgIssueStatus::IssueStatusDeleted(dropped_id, _count)) => {
let mut old = vec![]; let mut old = vec![];
std::mem::swap(&mut model.issue_statuses, &mut old); std::mem::swap(&mut model.issue_statuses, &mut old);
for is in old { for is in old {
@ -230,7 +231,7 @@ pub fn update(msg: WsMsg, model: &mut Model, orders: &mut impl Orders<Msg>) {
)); ));
} }
// issues // issues
WsMsg::ProjectIssuesLoaded(mut v) => { WsMsg::Project(WsMsgProject::ProjectIssuesLoaded(mut v)) => {
v.sort_by(|a, b| (a.list_position as i64).cmp(&(b.list_position as i64))); v.sort_by(|a, b| (a.list_position as i64).cmp(&(b.list_position as i64)));
{ {
let _ = std::mem::replace(model.issues_mut(), v.clone()); let _ = std::mem::replace(model.issues_mut(), v.clone());
@ -246,7 +247,7 @@ pub fn update(msg: WsMsg, model: &mut Model, orders: &mut impl Orders<Msg>) {
None, None,
)); ));
} }
WsMsg::IssueUpdated(issue) => { WsMsg::Issue(WsMsgIssue::IssueUpdated(issue)) => {
let id = issue.id; let id = issue.id;
model.issues_by_id.remove(&id); model.issues_by_id.remove(&id);
model.issues_by_id.insert(id, issue.clone()); model.issues_by_id.insert(id, issue.clone());
@ -259,7 +260,7 @@ pub fn update(msg: WsMsg, model: &mut Model, orders: &mut impl Orders<Msg>) {
Some(id), Some(id),
)); ));
} }
WsMsg::IssueDeleted(id, _count) => { WsMsg::Issue(WsMsgIssue::IssueDeleted(id, _count)) => {
let mut old = vec![]; let mut old = vec![];
std::mem::swap(model.issues_mut(), &mut old); std::mem::swap(model.issues_mut(), &mut old);
for is in old { for is in old {
@ -275,7 +276,7 @@ pub fn update(msg: WsMsg, model: &mut Model, orders: &mut impl Orders<Msg>) {
)); ));
} }
// users // users
WsMsg::ProjectUsersLoaded(v) => { WsMsg::Project(WsMsgProject::ProjectUsersLoaded(v)) => {
model.users = v.clone(); model.users = v.clone();
model.users_by_id.clear(); model.users_by_id.clear();
for user in v { for user in v {
@ -288,7 +289,7 @@ pub fn update(msg: WsMsg, model: &mut Model, orders: &mut impl Orders<Msg>) {
)); ));
} }
// comments // comments
WsMsg::IssueCommentsLoaded(mut comments) => { WsMsg::Comment(WsMsgComment::IssueCommentsLoaded(mut comments)) => {
let issue_id = match &model.modals().edit_issue { let issue_id = match &model.modals().edit_issue {
Some(modal) => modal.id, Some(modal) => modal.id,
_ => return, _ => return,
@ -307,7 +308,7 @@ pub fn update(msg: WsMsg, model: &mut Model, orders: &mut impl Orders<Msg>) {
None, None,
)); ));
} }
WsMsg::CommentUpdated(comment) => { WsMsg::Comment(WsMsgComment::CommentUpdated(comment)) => {
let comment_id = comment.id; let comment_id = comment.id;
if let Some(idx) = model.comments.iter().position(|c| c.id == comment.id) { if let Some(idx) = model.comments.iter().position(|c| c.id == comment.id) {
let _ = std::mem::replace(&mut model.comments[idx], comment.clone()); let _ = std::mem::replace(&mut model.comments[idx], comment.clone());
@ -319,7 +320,7 @@ pub fn update(msg: WsMsg, model: &mut Model, orders: &mut impl Orders<Msg>) {
Some(comment_id), Some(comment_id),
)); ));
} }
WsMsg::CommentDeleted(comment_id, _count) => { WsMsg::Comment(WsMsgComment::CommentDeleted(comment_id, _count)) => {
if let Some(idx) = model.comments.iter().position(|c| c.id == comment_id) { if let Some(idx) = model.comments.iter().position(|c| c.id == comment_id) {
model.comments.remove(idx); model.comments.remove(idx);
} }
@ -381,7 +382,7 @@ pub fn update(msg: WsMsg, model: &mut Model, orders: &mut impl Orders<Msg>) {
} }
// epics // epics
WsMsg::EpicsLoaded(epics) => { WsMsg::Epic(WsMsgEpic::EpicsLoaded(epics)) => {
model.epics = epics.clone(); model.epics = epics.clone();
for epic in epics { for epic in epics {
model.epics_by_id.insert(epic.id, epic); model.epics_by_id.insert(epic.id, epic);
@ -392,7 +393,7 @@ pub fn update(msg: WsMsg, model: &mut Model, orders: &mut impl Orders<Msg>) {
None, None,
)); ));
} }
WsMsg::EpicCreated(epic) => { WsMsg::Epic(WsMsgEpic::EpicCreated(epic)) => {
let id = epic.id; let id = epic.id;
model.epics.push(epic.clone()); model.epics.push(epic.clone());
model.epics.sort_by(|a, b| a.id.cmp(&b.id)); model.epics.sort_by(|a, b| a.id.cmp(&b.id));
@ -403,7 +404,7 @@ pub fn update(msg: WsMsg, model: &mut Model, orders: &mut impl Orders<Msg>) {
Some(id), Some(id),
)); ));
} }
WsMsg::EpicUpdated(epic) => { WsMsg::Epic(WsMsgEpic::EpicUpdated(epic)) => {
let epic_id = epic.id; let epic_id = epic.id;
if let Some(idx) = model.epics.iter().position(|e| e.id == epic.id) { if let Some(idx) = model.epics.iter().position(|e| e.id == epic.id) {
let _ = std::mem::replace(&mut model.epics[idx], epic.clone()); let _ = std::mem::replace(&mut model.epics[idx], epic.clone());
@ -416,7 +417,7 @@ pub fn update(msg: WsMsg, model: &mut Model, orders: &mut impl Orders<Msg>) {
Some(epic_id), Some(epic_id),
)); ));
} }
WsMsg::EpicDeleted(id, _count) => { WsMsg::Epic(WsMsgEpic::EpicDeleted(id, _count)) => {
if let Some(idx) = model.epics.iter().position(|e| e.id == id) { if let Some(idx) = model.epics.iter().position(|e| e.id == id) {
model.epics.remove(idx); model.epics.remove(idx);
} }

View File

@ -23,29 +23,9 @@ actix = { version = "0.10.0" }
dotenv = { version = "*" } dotenv = { version = "*" }
byteorder = "1.0"
chrono = { version = "0.4", features = ["serde"] }
time = { version = "0.1" }
url = { version = "2.1.0" }
percent-encoding = { version = "2.1.0" }
uuid = { version = "0.8.1", features = ["serde", "v4", "v5"] }
ipnetwork = { version = ">=0.12.2, <0.17.0" }
num-bigint = { version = ">=0.1.41, <0.3" }
num-traits = { version = "0.2" }
num-integer = { version = "0.1.32" }
bigdecimal = { version = ">= 0.0.10, <= 0.1.0" }
bitflags = { version = "1.0" }
serde = { version = "*", features = ["derive"] } serde = { version = "*", features = ["derive"] }
serde_json = { version = ">=0.8.0, <2.0" } serde_json = { version = ">=0.8.0, <2.0" }
toml = { version = "0.5.6" } toml = { version = "0.5.6" }
bincode = { version = "1.2.1" }
log = { version = "0.4" }
pretty_env_logger = { version = "0.4" }
env_logger = { version = "0.7" }
async-trait = { version = "*" }
futures = { version = "*" } futures = { version = "*" }
openssl-sys = { version = "*", features = ["vendored"] } openssl-sys = { version = "*", features = ["vendored"] }

View File

@ -120,27 +120,60 @@ impl WsError {
} }
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] #[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub enum WsMsg { pub enum WsMsgIssue {
Ping, IssueUpdate(IssueId, IssueFieldId, PayloadVariant),
Pong, IssueUpdated(Issue),
Die, IssueDelete(IssueId),
IssueDeleted(IssueId, NumberOfDeleted),
IssueCreate(CreateIssuePayload),
IssueCreated(Issue),
IssueSyncListPosition(Vec<(IssueId, ListPosition, IssueStatusId, Option<IssueId>)>),
}
// auth impl From<WsMsgIssue> for WsMsg {
AuthorizeLoad(Uuid), fn from(msg: WsMsgIssue) -> Self {
AuthorizeLoaded(Result<(User, UserSetting), String>), WsMsg::Issue(msg)
AuthorizeExpired, }
AuthenticateRequest(EmailString, UsernameString), }
AuthenticateSuccess,
BindTokenCheck(Uuid),
BindTokenBad,
BindTokenOk(Uuid),
// Sign up #[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
SignUpRequest(EmailString, UsernameString), pub enum WsMsgIssueStatus {
SignUpSuccess, IssueStatusesLoad,
SignUpPairTaken, IssueStatusesLoaded(Vec<IssueStatus>),
IssueStatusUpdate(IssueStatusId, TitleString, Position),
IssueStatusUpdated(IssueStatus),
IssueStatusCreate(TitleString, Position),
IssueStatusCreated(IssueStatus),
IssueStatusDelete(IssueStatusId),
IssueStatusDeleted(IssueStatusId, NumberOfDeleted),
}
// invitations impl From<WsMsgIssueStatus> for WsMsg {
fn from(msg: WsMsgIssueStatus) -> Self {
WsMsg::IssueStatus(msg)
}
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub enum WsMsgComment {
IssueCommentsLoad(IssueId),
IssueCommentsLoaded(Vec<Comment>),
CommentCreate(CreateCommentPayload),
CommentCreated(Comment),
CommentUpdate(UpdateCommentPayload),
CommentUpdated(Comment),
CommentDelete(CommentId),
CommentDeleted(CommentId, NumberOfDeleted),
}
impl From<WsMsgComment> for WsMsg {
fn from(msg: WsMsgComment) -> Self {
WsMsg::Comment(msg)
}
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub enum WsMsgInvitation {
InvitationListLoad, InvitationListLoad,
InvitationListLoaded(Vec<Invitation>), InvitationListLoaded(Vec<Invitation>),
// //
@ -168,8 +201,35 @@ pub enum WsMsg {
// //
InvitedUserRemoveRequest(UserId), InvitedUserRemoveRequest(UserId),
InvitedUserRemoveSuccess(UserId), InvitedUserRemoveSuccess(UserId),
}
// project page impl From<WsMsgInvitation> for WsMsg {
fn from(msg: WsMsgInvitation) -> Self {
WsMsg::Invitation(msg)
}
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub enum WsMsgEpic {
EpicsLoad,
EpicsLoaded(Vec<Epic>),
EpicCreate(
NameString,
Option<DescriptionString>,
Option<DescriptionString>,
),
EpicCreated(Epic),
EpicUpdateName(EpicId, NameString),
EpicUpdateStartsAt(EpicId, Option<StartsAt>),
EpicUpdateEndsAt(EpicId, Option<EndsAt>),
EpicUpdated(Epic),
EpicDelete(EpicId),
EpicDeleted(EpicId, NumberOfDeleted),
EpicTransform(EpicId, IssueType),
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub enum WsMsgProject {
ProjectsLoad, ProjectsLoad,
ProjectsLoaded(Vec<Project>), ProjectsLoaded(Vec<Project>),
@ -178,35 +238,49 @@ pub enum WsMsg {
ProjectUsersLoad, ProjectUsersLoad,
ProjectUsersLoaded(Vec<User>), ProjectUsersLoaded(Vec<User>),
ProjectUpdateLoad(UpdateProjectPayload), ProjectUpdateLoad(UpdateProjectPayload),
}
impl From<WsMsgProject> for WsMsg {
fn from(msg: WsMsgProject) -> Self {
WsMsg::Project(msg)
}
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub enum WsMsg {
Ping,
Pong,
Die,
// auth
AuthorizeLoad(Uuid),
AuthorizeLoaded(Result<(User, UserSetting), String>),
AuthorizeExpired,
AuthenticateRequest(EmailString, UsernameString),
AuthenticateSuccess,
BindTokenCheck(Uuid),
BindTokenBad,
BindTokenOk(Uuid),
// Sign up
SignUpRequest(EmailString, UsernameString),
SignUpSuccess,
SignUpPairTaken,
// invitations
Invitation(WsMsgInvitation),
// project page
Project(WsMsgProject),
// issue // issue
IssueUpdate(IssueId, IssueFieldId, PayloadVariant), Issue(WsMsgIssue),
IssueUpdated(Issue),
IssueDelete(IssueId),
IssueDeleted(IssueId, NumberOfDeleted),
IssueCreate(CreateIssuePayload),
IssueCreated(Issue),
IssueSyncListPosition(Vec<(IssueId, ListPosition, IssueStatusId, Option<IssueId>)>),
// issue status // issue status
IssueStatusesLoad, IssueStatus(WsMsgIssueStatus),
IssueStatusesLoaded(Vec<IssueStatus>),
IssueStatusUpdate(IssueStatusId, TitleString, Position),
IssueStatusUpdated(IssueStatus),
IssueStatusCreate(TitleString, Position),
IssueStatusCreated(IssueStatus),
IssueStatusDelete(IssueStatusId),
IssueStatusDeleted(IssueStatusId, NumberOfDeleted),
// comments // comments
IssueCommentsLoad(IssueId), Comment(WsMsgComment),
IssueCommentsLoaded(Vec<Comment>),
CommentCreate(CreateCommentPayload),
CommentCreated(Comment),
CommentUpdate(UpdateCommentPayload),
CommentUpdated(Comment),
CommentDelete(CommentId),
CommentDeleted(CommentId, NumberOfDeleted),
// users // users
AvatarUrlChanged(UserId, AvatarUrl), AvatarUrlChanged(UserId, AvatarUrl),
@ -231,21 +305,7 @@ pub enum WsMsg {
MessageMarkedSeen(MessageId, NumberOfDeleted), MessageMarkedSeen(MessageId, NumberOfDeleted),
// epics // epics
EpicsLoad, Epic(WsMsgEpic),
EpicsLoaded(Vec<Epic>),
EpicCreate(
NameString,
Option<DescriptionString>,
Option<DescriptionString>,
),
EpicCreated(Epic),
EpicUpdateName(EpicId, NameString),
EpicUpdateStartsAt(EpicId, Option<StartsAt>),
EpicUpdateEndsAt(EpicId, Option<EndsAt>),
EpicUpdated(Epic),
EpicDelete(EpicId),
EpicDeleted(EpicId, NumberOfDeleted),
EpicTransform(EpicId, IssueType),
// highlight // highlight
HighlightCode(Lang, Code), HighlightCode(Lang, Code),