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

View File

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

View File

@ -15,24 +15,25 @@ pub struct Authenticate {
pub email: String,
}
impl WsHandler<Authenticate> for WebSocketActor {
fn handle_msg(&mut self, msg: Authenticate, _ctx: &mut Self::Context) -> WsResult {
#[async_trait::async_trait]
impl AsyncHandler<Authenticate> for WebSocketActor {
async fn exec(&mut self, msg: Authenticate) -> WsResult {
let Authenticate { name, email } = msg;
// TODO check attempt number, allow only 5 times per day
let user = db_or_debug_and_return!(
self,
LookupUser { name, email },
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() {
let _ = mail_or_debug_and_return!(
self,
Welcome {
bind_token,
Welcome {bind_token,
email: user.email,
}
}; async
);
}
Ok(Some(WsMsg::AuthenticateSuccess))
@ -76,15 +77,16 @@ pub struct CheckBindToken {
pub bind_token: uuid::Uuid,
}
impl WsHandler<CheckBindToken> for WebSocketActor {
fn handle_msg(&mut self, msg: CheckBindToken, _ctx: &mut Self::Context) -> WsResult {
#[async_trait::async_trait]
impl AsyncHandler<CheckBindToken> for WebSocketActor {
async fn exec(&mut self, msg: CheckBindToken) -> WsResult {
let token: Token = db_or_debug_and_return!(
self,
FindBindToken {
token: msg.bind_token,
},
Ok(Some(WsMsg::BindTokenBad)),
Ok(None)
Ok(None); async
);
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 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 issue_id: IssueId,
}
impl WsHandler<LoadIssueComments> for WebSocketActor {
fn handle_msg(&mut self, msg: LoadIssueComments, _ctx: &mut Self::Context) -> WsResult {
#[async_trait::async_trait]
impl AsyncHandler<LoadIssueComments> for WebSocketActor {
async fn exec(&mut self, msg: LoadIssueComments) -> WsResult {
self.require_user()?;
let comments = db_or_debug_and_return!(
self,
database_actor::comments::LoadIssueComments {
issue_id: msg.issue_id,
}
}; async
);
Ok(Some(WsMsg::IssueCommentsLoaded(comments)))
Ok(Some(WsMsg::Comment(WsMsgComment::IssueCommentsLoaded(
comments,
))))
}
}
impl WsHandler<CreateCommentPayload> for WebSocketActor {
fn handle_msg(&mut self, mut msg: CreateCommentPayload, ctx: &mut Self::Context) -> WsResult {
#[async_trait::async_trait]
impl AsyncHandler<CreateCommentPayload> for WebSocketActor {
async fn exec(&mut self, mut msg: CreateCommentPayload) -> WsResult {
use database_actor::comments::CreateComment;
let user_id = self.require_user()?.id;
@ -37,14 +61,15 @@ impl WsHandler<CreateCommentPayload> for WebSocketActor {
user_id,
issue_id,
body: msg.body,
}
}; async
);
self.handle_msg(LoadIssueComments { issue_id }, ctx)
self.exec(LoadIssueComments { issue_id }).await
}
}
impl WsHandler<UpdateCommentPayload> for WebSocketActor {
fn handle_msg(&mut self, msg: UpdateCommentPayload, _ctx: &mut Self::Context) -> WsResult {
#[async_trait::async_trait]
impl AsyncHandler<UpdateCommentPayload> for WebSocketActor {
async fn exec(&mut self, msg: UpdateCommentPayload) -> WsResult {
use database_actor::comments::UpdateComment;
let user_id = self.require_user()?.id;
@ -60,9 +85,9 @@ impl WsHandler<UpdateCommentPayload> for WebSocketActor {
comment_id,
user_id,
body,
}
}; async
);
self.broadcast(&WsMsg::CommentUpdated(comment));
self.broadcast(&WsMsg::Comment(WsMsgComment::CommentUpdated(comment)));
Ok(None)
}
}
@ -71,8 +96,9 @@ pub struct DeleteComment {
pub comment_id: CommentId,
}
impl WsHandler<DeleteComment> for WebSocketActor {
fn handle_msg(&mut self, msg: DeleteComment, _ctx: &mut Self::Context) -> WsResult {
#[async_trait::async_trait]
impl AsyncHandler<DeleteComment> for WebSocketActor {
async fn exec(&mut self, msg: DeleteComment) -> WsResult {
use database_actor::comments::DeleteComment;
let user_id = self.require_user()?.id;
@ -82,8 +108,11 @@ impl WsHandler<DeleteComment> for WebSocketActor {
DeleteComment {
comment_id: msg.comment_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::{
DescriptionString, EndsAt, EpicId, IssueType, NameString, StartsAt, UserProject, WsMsg,
};
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;
impl WsHandler<LoadEpics> for WebSocketActor {
fn handle_msg(&mut self, _msg: LoadEpics, _ctx: &mut Self::Context) -> WsResult {
#[async_trait::async_trait]
impl AsyncHandler<LoadEpics> for WebSocketActor {
async fn exec(&mut self, _msg: LoadEpics) -> WsResult {
let project_id = self.require_user_project()?.project_id;
let epics = db_or_debug_and_return!(self, database_actor::epics::LoadEpics { project_id });
Ok(Some(WsMsg::EpicsLoaded(epics)))
let 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>,
}
impl WsHandler<CreateEpic> for WebSocketActor {
fn handle_msg(&mut self, msg: CreateEpic, _ctx: &mut Self::Context) -> WsResult {
#[async_trait::async_trait]
impl AsyncHandler<CreateEpic> for WebSocketActor {
async fn exec(&mut self, msg: CreateEpic) -> WsResult {
let CreateEpic {
name,
description,
@ -41,9 +84,9 @@ impl WsHandler<CreateEpic> for WebSocketActor {
description,
description_html,
name,
}
}; async
);
Ok(Some(WsMsg::EpicCreated(epic)))
Ok(Some(WsMsg::Epic(WsMsgEpic::EpicCreated(epic))))
}
}
@ -52,8 +95,9 @@ pub struct UpdateEpicName {
pub name: NameString,
}
impl WsHandler<UpdateEpicName> for WebSocketActor {
fn handle_msg(&mut self, msg: UpdateEpicName, _ctx: &mut Self::Context) -> WsResult {
#[async_trait::async_trait]
impl AsyncHandler<UpdateEpicName> for WebSocketActor {
async fn exec(&mut self, msg: UpdateEpicName) -> WsResult {
let UserProject { project_id, .. } = self.require_user_project()?;
let epic = db_or_debug_and_return!(
self,
@ -61,9 +105,9 @@ impl WsHandler<UpdateEpicName> for WebSocketActor {
project_id: *project_id,
epic_id: msg.epic_id,
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>,
}
impl WsHandler<UpdateEpicStartsAt> for WebSocketActor {
fn handle_msg(&mut self, msg: UpdateEpicStartsAt, _ctx: &mut Self::Context) -> WsResult {
#[async_trait::async_trait]
impl AsyncHandler<UpdateEpicStartsAt> for WebSocketActor {
async fn exec(&mut self, msg: UpdateEpicStartsAt) -> WsResult {
let UserProject { project_id, .. } = self.require_user_project()?;
let epic = db_or_debug_and_return!(
self,
@ -81,9 +126,9 @@ impl WsHandler<UpdateEpicStartsAt> for WebSocketActor {
project_id: *project_id,
epic_id: msg.epic_id,
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>,
}
impl WsHandler<UpdateEpicEndsAt> for WebSocketActor {
fn handle_msg(&mut self, msg: UpdateEpicEndsAt, _ctx: &mut Self::Context) -> WsResult {
#[async_trait::async_trait]
impl AsyncHandler<UpdateEpicEndsAt> for WebSocketActor {
async fn exec(&mut self, msg: UpdateEpicEndsAt) -> WsResult {
let UserProject { project_id, .. } = self.require_user_project()?;
let epic = db_or_debug_and_return!(
self,
@ -101,9 +147,9 @@ impl WsHandler<UpdateEpicEndsAt> for WebSocketActor {
project_id: *project_id,
epic_id: msg.epic_id,
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,
}
impl WsHandler<DeleteEpic> for WebSocketActor {
fn handle_msg(&mut self, msg: DeleteEpic, _ctx: &mut Self::Context) -> WsResult {
#[async_trait::async_trait]
impl AsyncHandler<DeleteEpic> for WebSocketActor {
async fn exec(&mut self, msg: DeleteEpic) -> WsResult {
let DeleteEpic { epic_id } = msg;
let UserProject { user_id, .. } = self.require_user_project()?;
let n = db_or_debug_and_return!(
@ -120,9 +167,9 @@ impl WsHandler<DeleteEpic> for WebSocketActor {
database_actor::epics::DeleteEpic {
user_id: *user_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,
}
impl WsHandler<TransformEpic> for WebSocketActor {
fn handle_msg(&mut self, msg: TransformEpic, _ctx: &mut Self::Context) -> WsResult {
#[async_trait::async_trait]
impl AsyncHandler<TransformEpic> for WebSocketActor {
async fn exec(&mut self, msg: TransformEpic) -> WsResult {
let epic: jirs_data::Epic = db_or_debug_and_return!(
self,
database_actor::epics::FindEpic {
epic_id: msg.epic_id
}
}; async
);
let issue: database_actor::models::Issue = db_or_debug_and_return!(
self,
@ -155,17 +203,17 @@ impl WsHandler<TransformEpic> for WebSocketActor {
reporter_id: epic.user_id,
user_ids: vec![epic.user_id],
epic_id: None
}
}; async
);
let n = db_or_debug_and_return!(
self,
database_actor::epics::DeleteEpic {
user_id: epic.user_id,
epic_id: epic.id
}
}; async
);
self.broadcast(&WsMsg::EpicDeleted(msg.epic_id, n));
self.broadcast(&WsMsg::IssueCreated(issue.into()));
self.broadcast(&WsMsg::Epic(WsMsgEpic::EpicDeleted(msg.epic_id, n)));
self.broadcast(&WsMsg::Issue(WsMsgIssue::IssueCreated(issue.into())));
Ok(None)
}
}

View File

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

View File

@ -1,26 +1,64 @@
use database_actor::invitations;
use database_actor::messages::CreateMessageReceiver;
use futures::executor::block_on;
use jirs_data::msg::WsMsgInvitation;
use jirs_data::{
EmailString, InvitationId, InvitationToken, MessageType, UserRole, UsernameString, WsMsg,
};
use crate::handlers::{LoadInvitedUsers, RemoveInvitedUser};
use crate::server::InnerMsg;
use crate::{
db_or_debug_and_return, mail_or_debug_and_return, WebSocketActor, WsHandler, WsMessageSender,
WsResult,
db_or_debug_and_return, mail_or_debug_and_return, AsyncHandler, WebSocketActor, WsHandler,
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;
impl WsHandler<ListInvitation> for WebSocketActor {
fn handle_msg(&mut self, _msg: ListInvitation, _ctx: &mut Self::Context) -> WsResult {
#[async_trait::async_trait]
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) {
Some(id) => id,
_ => return Ok(None),
};
let v = db_or_debug_and_return!(self, invitations::ListInvitation { user_id });
Ok(Some(WsMsg::InvitationListLoaded(v)))
let v = db_or_debug_and_return!(self, invitations::ListInvitation { user_id }; async);
Ok(Some(WsMsg::Invitation(
WsMsgInvitation::InvitationListLoaded(v),
)))
}
}
@ -30,8 +68,9 @@ pub struct CreateInvitation {
pub role: UserRole,
}
impl WsHandler<CreateInvitation> for WebSocketActor {
fn handle_msg(&mut self, msg: CreateInvitation, _ctx: &mut Self::Context) -> WsResult {
#[async_trait::async_trait]
impl AsyncHandler<CreateInvitation> for WebSocketActor {
async fn exec(&mut self, msg: CreateInvitation) -> WsResult {
let project_id = match self.current_user_project.as_ref() {
Some(up) => up.project_id,
_ => return Ok(None),
@ -48,8 +87,8 @@ impl WsHandler<CreateInvitation> for WebSocketActor {
name: name.clone(),
role,
},
Ok(Some(WsMsg::InvitationSendFailure)),
Ok(Some(WsMsg::InvitationSendFailure))
Ok(Some(WsMsg::Invitation(WsMsgInvitation::InvitationSendFailure))),
Ok(Some(WsMsg::Invitation(WsMsgInvitation::InvitationSendFailure))); async
);
let _ = mail_or_debug_and_return!(
self,
@ -58,8 +97,8 @@ impl WsHandler<CreateInvitation> for WebSocketActor {
email: invitation.email,
inviter_name,
},
Ok(Some(WsMsg::InvitationSendFailure)),
Ok(Some(WsMsg::InvitationSendFailure))
Ok(Some(WsMsg::Invitation(WsMsgInvitation::InvitationSendFailure))),
Ok(Some(WsMsg::Invitation(WsMsgInvitation::InvitationSendFailure))); async
);
// 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,
}
impl WsHandler<DeleteInvitation> for WebSocketActor {
fn handle_msg(&mut self, msg: DeleteInvitation, _ctx: &mut Self::Context) -> WsResult {
#[async_trait::async_trait]
impl AsyncHandler<DeleteInvitation> for WebSocketActor {
async fn exec(&mut self, msg: DeleteInvitation) -> WsResult {
self.require_user()?;
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)
}
}
@ -98,12 +140,15 @@ pub struct RevokeInvitation {
pub id: InvitationId,
}
impl WsHandler<RevokeInvitation> for WebSocketActor {
fn handle_msg(&mut self, msg: RevokeInvitation, _ctx: &mut Self::Context) -> WsResult {
#[async_trait::async_trait]
impl AsyncHandler<RevokeInvitation> for WebSocketActor {
async fn exec(&mut self, msg: RevokeInvitation) -> WsResult {
self.require_user()?;
let RevokeInvitation { id } = msg;
let _ = db_or_debug_and_return!(self, invitations::RevokeInvitation { id });
Ok(Some(WsMsg::InvitationRevokeSuccess(id)))
let _ = db_or_debug_and_return!(self, invitations::RevokeInvitation { id }; async);
Ok(Some(WsMsg::Invitation(
WsMsgInvitation::InvitationRevokeSuccess(id),
)))
}
}
@ -117,8 +162,12 @@ impl WsHandler<AcceptInvitation> for WebSocketActor {
let token = db_or_debug_and_return!(
self,
invitations::AcceptInvitation { invitation_token },
Ok(Some(WsMsg::InvitationAcceptFailure(invitation_token))),
Ok(Some(WsMsg::InvitationAcceptFailure(invitation_token)))
Ok(Some(WsMsg::Invitation(
WsMsgInvitation::InvitationAcceptFailure(invitation_token)
))),
Ok(Some(WsMsg::Invitation(
WsMsgInvitation::InvitationAcceptFailure(invitation_token)
)))
);
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 futures::executor::block_on;
use jirs_data::msg::WsMsgIssueStatus;
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;
impl WsHandler<LoadIssueStatuses> for WebSocketActor {
fn handle_msg(&mut self, _msg: LoadIssueStatuses, _ctx: &mut Self::Context) -> WsResult {
#[async_trait::async_trait]
impl AsyncHandler<LoadIssueStatuses> for WebSocketActor {
async fn exec(&mut self, _msg: LoadIssueStatuses) -> WsResult {
let project_id = self.require_user_project()?.project_id;
let v = db_or_debug_and_return!(self, issue_statuses::LoadIssueStatuses { project_id });
Ok(Some(WsMsg::IssueStatusesLoaded(v)))
let 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,
}
impl WsHandler<CreateIssueStatus> for WebSocketActor {
fn handle_msg(&mut self, msg: CreateIssueStatus, _ctx: &mut Self::Context) -> WsResult {
#[async_trait::async_trait]
impl AsyncHandler<CreateIssueStatus> for WebSocketActor {
async fn exec(&mut self, msg: CreateIssueStatus) -> WsResult {
let project_id = self.require_user_project()?.project_id;
let CreateIssueStatus { position, name } = msg;
@ -31,9 +63,11 @@ impl WsHandler<CreateIssueStatus> for WebSocketActor {
project_id,
position,
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,
}
impl WsHandler<DeleteIssueStatus> for WebSocketActor {
fn handle_msg(&mut self, msg: DeleteIssueStatus, _ctx: &mut Self::Context) -> WsResult {
#[async_trait::async_trait]
impl AsyncHandler<DeleteIssueStatus> for WebSocketActor {
async fn exec(&mut self, msg: DeleteIssueStatus) -> WsResult {
let project_id = self.require_user_project()?.project_id;
let DeleteIssueStatus { issue_status_id } = msg;
@ -51,9 +86,11 @@ impl WsHandler<DeleteIssueStatus> for WebSocketActor {
issue_statuses::DeleteIssueStatus {
project_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,
}
impl WsHandler<UpdateIssueStatus> for WebSocketActor {
fn handle_msg(&mut self, msg: UpdateIssueStatus, _ctx: &mut Self::Context) -> WsResult {
#[async_trait::async_trait]
impl AsyncHandler<UpdateIssueStatus> for WebSocketActor {
async fn exec(&mut self, msg: UpdateIssueStatus) -> WsResult {
let project_id = self.require_user_project()?.project_id;
let UpdateIssueStatus {
@ -79,9 +117,11 @@ impl WsHandler<UpdateIssueStatus> for WebSocketActor {
project_id,
position,
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() {
self.broadcast(ws_msg)
}

View File

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

View File

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

View File

@ -1,11 +1,28 @@
use database_actor as db;
use futures::executor::block_on;
use jirs_data::msg::WsMsgProject;
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 {
fn handle_msg(&mut self, msg: UpdateProjectPayload, _ctx: &mut Self::Context) -> WsResult {
#[async_trait::async_trait]
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 {
user_id,
project_id,
@ -20,22 +37,23 @@ impl WsHandler<UpdateProjectPayload> for WebSocketActor {
description: msg.description,
category: msg.category,
time_tracking: msg.time_tracking,
}
}; async
);
let projects = db_or_debug_and_return!(
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;
impl WsHandler<LoadProjects> for WebSocketActor {
fn handle_msg(&mut self, _msg: LoadProjects, _ctx: &mut Self::Context) -> WsResult {
#[async_trait::async_trait]
impl AsyncHandler<LoadProjects> for WebSocketActor {
async fn exec(&mut self, _msg: LoadProjects) -> WsResult {
let user_id = self.require_user()?.id;
let v = db_or_debug_and_return!(self, db::projects::LoadProjects { user_id });
Ok(Some(WsMsg::ProjectsLoaded(v)))
let v = db_or_debug_and_return!(self, db::projects::LoadProjects { user_id }; async);
Ok(Some(WsMsg::Project(WsMsgProject::ProjectsLoaded(v))))
}
}

View File

@ -1,15 +1,16 @@
use database_actor as db;
use futures::executor::block_on;
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;
impl WsHandler<LoadUserProjects> for WebSocketActor {
fn handle_msg(&mut self, _msg: LoadUserProjects, _ctx: &mut Self::Context) -> WsResult {
#[async_trait::async_trait]
impl AsyncHandler<LoadUserProjects> for WebSocketActor {
async fn exec(&mut self, _msg: LoadUserProjects) -> WsResult {
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)))
}
}
@ -18,15 +19,16 @@ pub struct SetCurrentUserProject {
pub id: UserProjectId,
}
impl WsHandler<SetCurrentUserProject> for WebSocketActor {
fn handle_msg(&mut self, msg: SetCurrentUserProject, _ctx: &mut Self::Context) -> WsResult {
#[async_trait::async_trait]
impl AsyncHandler<SetCurrentUserProject> for WebSocketActor {
async fn exec(&mut self, msg: SetCurrentUserProject) -> WsResult {
let user_id = self.require_user()?.id;
let user_project = db_or_debug_and_return!(
self,
db::user_projects::ChangeCurrentUserProject {
user_id,
id: msg.id,
}
}; async
);
self.current_user_project = Some(user_project.clone());
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 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 {
UserSetting {
@ -15,15 +14,16 @@ pub struct SetTextEditorMode {
pub mode: TextEditorMode,
}
impl WsHandler<SetTextEditorMode> for WebSocketActor {
fn handle_msg(&mut self, msg: SetTextEditorMode, _ctx: &mut Self::Context) -> WsResult {
#[async_trait::async_trait]
impl AsyncHandler<SetTextEditorMode> for WebSocketActor {
async fn exec(&mut self, msg: SetTextEditorMode) -> WsResult {
let user_id = self.require_user()?.id;
let setting = db_or_debug_and_return!(
self,
database_actor::user_settings::UpdateUserSetting {
user_id,
mode: msg.mode
}
}; async
);
Ok(Some(WsMsg::UserSettingUpdated(setting)))
}

View File

@ -1,20 +1,21 @@
use database_actor::users::Register as DbRegister;
use database_actor::{self};
use futures::executor::block_on;
use jirs_data::msg::{WsMsgInvitation, WsMsgProject};
use jirs_data::{UserId, UserProject, UserRole, WsMsg};
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;
impl WsHandler<LoadProjectUsers> for WebSocketActor {
fn handle_msg(&mut self, _msg: LoadProjectUsers, _ctx: &mut Self::Context) -> WsResult {
#[async_trait::async_trait]
impl AsyncHandler<LoadProjectUsers> for WebSocketActor {
async fn exec(&mut self, _msg: LoadProjectUsers) -> WsResult {
use database_actor::users::LoadProjectUsers as Msg;
let project_id = self.require_user_project()?.project_id;
let v = db_or_debug_and_return!(self, Msg { project_id });
Ok(Some(WsMsg::ProjectUsersLoaded(v)))
let v = db_or_debug_and_return!(self, Msg { project_id }; async);
Ok(Some(WsMsg::Project(WsMsgProject::ProjectUsersLoaded(v))))
}
}
@ -23,8 +24,9 @@ pub struct Register {
pub email: String,
}
impl WsHandler<Register> for WebSocketActor {
fn handle_msg(&mut self, msg: Register, ctx: &mut Self::Context) -> WsResult {
#[async_trait::async_trait]
impl AsyncHandler<Register> for WebSocketActor {
async fn exec(&mut self, msg: Register) -> WsResult {
let Register { name, email } = msg;
let _ = db_or_debug_and_return!(
self,
@ -35,10 +37,10 @@ impl WsHandler<Register> for WebSocketActor {
role: UserRole::Owner,
},
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(_) => (),
Err(e) => return Ok(Some(e)),
};
@ -49,14 +51,16 @@ impl WsHandler<Register> for WebSocketActor {
pub struct LoadInvitedUsers;
impl WsHandler<LoadInvitedUsers> for WebSocketActor {
fn handle_msg(&mut self, _msg: LoadInvitedUsers, _ctx: &mut Self::Context) -> WsResult {
#[async_trait::async_trait]
impl AsyncHandler<LoadInvitedUsers> for WebSocketActor {
async fn exec(&mut self, _msg: LoadInvitedUsers) -> WsResult {
let user_id = self.require_user()?.id;
let users =
db_or_debug_and_return!(self, database_actor::users::LoadInvitedUsers { user_id });
let users = db_or_debug_and_return!(self, database_actor::users::LoadInvitedUsers { user_id }; async);
Ok(Some(WsMsg::InvitedUsersLoaded(users)))
Ok(Some(WsMsg::Invitation(
WsMsgInvitation::InvitedUsersLoaded(users),
)))
}
}
@ -65,8 +69,9 @@ pub struct ProfileUpdate {
pub email: String,
}
impl WsHandler<ProfileUpdate> for WebSocketActor {
fn handle_msg(&mut self, msg: ProfileUpdate, _ctx: &mut Self::Context) -> WsResult {
#[async_trait::async_trait]
impl AsyncHandler<ProfileUpdate> for WebSocketActor {
async fn exec(&mut self, msg: ProfileUpdate) -> WsResult {
let user_id = self.require_user()?.id;
let ProfileUpdate { name, email } = msg;
@ -76,7 +81,7 @@ impl WsHandler<ProfileUpdate> for WebSocketActor {
user_id,
name,
email,
}
}; async
);
Ok(Some(WsMsg::ProfileUpdated))
@ -87,8 +92,9 @@ pub struct RemoveInvitedUser {
pub user_id: UserId,
}
impl WsHandler<RemoveInvitedUser> for WebSocketActor {
fn handle_msg(&mut self, msg: RemoveInvitedUser, _ctx: &mut Self::Context) -> WsResult {
#[async_trait::async_trait]
impl AsyncHandler<RemoveInvitedUser> for WebSocketActor {
async fn exec(&mut self, msg: RemoveInvitedUser) -> WsResult {
let RemoveInvitedUser {
user_id: invited_id,
} = msg;
@ -103,8 +109,10 @@ impl WsHandler<RemoveInvitedUser> for WebSocketActor {
invited_id,
inviter_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::user_projects::CurrentUserProject;
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 mail_actor::MailExecutor;
@ -80,154 +81,65 @@ impl WebSocketActor {
debug!("incoming message: {:?}", msg);
}
let msg = match msg {
WsMsg::Ping => Some(WsMsg::Pong),
WsMsg::Pong => Some(WsMsg::Ping),
// issues
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)?
match msg {
WsMsg::Ping => return Ok(Some(WsMsg::Pong)),
WsMsg::Pong => return Ok(Some(WsMsg::Ping)),
WsMsg::AuthorizeLoad(uuid) => {
return Ok(self.handle_msg(CheckAuthToken { token: uuid }, ctx)?)
}
WsMsg::ProjectIssuesLoad => self.handle_msg(LoadIssues, 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)?
WsMsg::Invitation(WsMsgInvitation::InvitationAcceptRequest(invitation_token)) => {
return Ok(self.handle_msg(AcceptInvitation { invitation_token }, ctx)?)
}
_ => {}
};
// projects
WsMsg::ProjectsLoad => self.handle_msg(LoadProjects, ctx)?,
WsMsg::ProjectUpdateLoad(payload) => self.handle_msg(payload, ctx)?,
let fut = match msg {
WsMsg::Project(m) => self.exec(m),
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
WsMsg::UserProjectsLoad => self.handle_msg(LoadUserProjects, ctx)?,
WsMsg::UserProjectSetCurrent(user_project_id) => self.handle_msg(
SetCurrentUserProject {
id: user_project_id,
},
ctx,
)?,
WsMsg::UserProjectsLoad => self.exec(LoadUserProjects),
WsMsg::UserProjectSetCurrent(user_project_id) => self.exec(SetCurrentUserProject {
id: user_project_id,
}),
// auth
WsMsg::AuthorizeLoad(uuid) => self.handle_msg(CheckAuthToken { token: uuid }, ctx)?,
WsMsg::BindTokenCheck(uuid) => {
self.handle_msg(CheckBindToken { bind_token: uuid }, ctx)?
}
WsMsg::AuthenticateRequest(email, name) => {
self.handle_msg(Authenticate { name, email }, ctx)?
}
WsMsg::BindTokenCheck(uuid) => self.exec(CheckBindToken { bind_token: uuid }),
WsMsg::AuthenticateRequest(email, name) => self.exec(Authenticate { name, email }),
// register
WsMsg::SignUpRequest(email, username) => self.handle_msg(
Register {
name: username,
email,
},
ctx,
)?,
// users
WsMsg::ProjectUsersLoad => self.handle_msg(LoadProjectUsers, ctx)?,
WsMsg::InvitedUserRemoveRequest(user_id) => {
self.handle_msg(RemoveInvitedUser { user_id }, ctx)?
}
WsMsg::SignUpRequest(email, username) => self.exec(Register {
name: username,
email,
}),
// user settings
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
WsMsg::ProfileUpdate(email, name) => {
self.handle_msg(ProfileUpdate { name, email }, ctx)?
}
WsMsg::ProfileUpdate(email, name) => self.exec(ProfileUpdate { name, email }),
// messages
WsMsg::MessagesLoad => self.handle_msg(LoadMessages, ctx)?,
WsMsg::MessageMarkSeen(id) => self.handle_msg(MarkMessageSeen { id }, ctx)?,
// 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,
)?,
WsMsg::MessagesLoad => self.exec(LoadMessages),
WsMsg::MessageMarkSeen(id) => self.exec(MarkMessageSeen { id }),
// hi
WsMsg::HighlightCode(lang, code) => {
self.handle_msg(hi::HighlightCode(lang, code), ctx)?
}
WsMsg::HighlightCode(lang, code) => self.exec(hi::HighlightCode(lang, code)),
// else fail
_ => {
error!("No handle for {:?} specified", msg);
None
return Ok(None);
}
};
let msg = wait(fut)?;
if msg.is_some() && msg != Some(WsMsg::Pong) {
info!("sending message {:?}", msg);
}
@ -251,8 +163,8 @@ impl WebSocketActor {
.send(InnerMsg::Join(project_id, user.id, addr))
.await
{
Err(e) => error!("{}", e),
_ => info!(" joined channel"),
Err(e) => common::log::error!("{:?}", e),
_ => common::log::info!(" joined channel"),
};
}
@ -268,7 +180,7 @@ impl WebSocketActor {
fn load_user_project(&self) -> Result<UserProject, WsMsg> {
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(Err(e)) => {
error!("load_user_project encounter service error {:?}", e);
@ -283,14 +195,14 @@ impl WebSocketActor {
fn load_project(&self) -> Result<Project, WsMsg> {
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(Err(e)) => {
error!("{:?}", e);
Err(WsMsg::AuthorizeExpired)
}
Err(e) => {
error!("{}", e);
error!("{:?}", e);
Err(WsMsg::AuthorizeExpired)
}
}
@ -347,6 +259,14 @@ where
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/")]
pub async fn index(
req: HttpRequest,

View File

@ -6,6 +6,12 @@ macro_rules! db_or_debug_and_return {
($s: ident, $msg: expr) => {
$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]
@ -16,6 +22,12 @@ macro_rules! db_or_debug_or_fallback {
($s: ident, $msg: expr) => {
$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]
@ -26,6 +38,12 @@ macro_rules! mail_or_debug_and_return {
($s: ident, $msg: expr) => {
$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]
@ -46,6 +64,22 @@ macro_rules! actor_or_debug_and_return {
($s: ident, $actor: ident, $msg: expr) => {
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]
@ -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]
@ -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 seed::prelude::*;
@ -12,7 +13,11 @@ pub fn update(msg: &Msg, model: &mut crate::model::Model, orders: &mut impl Orde
match msg {
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(_)) => {
orders.skip().send_msg(Msg::ModalDropped);

View File

@ -1,3 +1,4 @@
use jirs_data::msg::WsMsgEpic;
use jirs_data::{EpicFieldId, IssueType, WsMsg};
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) => {
let epic_id = modal.epic_id;
send_ws_msg(
WsMsg::EpicUpdateName(epic_id, s.to_string()),
WsMsg::Epic(WsMsgEpic::EpicUpdateName(epic_id, s.to_string())),
model.ws.as_ref(),
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;
send_ws_msg(
WsMsg::EpicUpdateStartsAt(epic_id, Some(*date)),
WsMsg::Epic(WsMsgEpic::EpicUpdateStartsAt(epic_id, Some(*date))),
model.ws.as_ref(),
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;
send_ws_msg(
WsMsg::EpicUpdateEndsAt(epic_id, Some(*date)),
WsMsg::Epic(WsMsgEpic::EpicUpdateEndsAt(epic_id, Some(*date))),
model.ws.as_ref(),
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 issue_type: IssueType = modal.transform_into.value.into();
send_ws_msg(
WsMsg::EpicTransform(epic_id, issue_type),
WsMsg::Epic(WsMsgEpic::EpicTransform(epic_id, issue_type)),
model.ws.as_ref(),
orders,
);

View File

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

View File

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

View File

@ -1,3 +1,4 @@
use jirs_data::msg::{WsMsgComment, WsMsgIssue};
use jirs_data::*;
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();
send_ws_msg(
WsMsg::IssueUpdate(
WsMsg::Issue(WsMsgIssue::IssueUpdate(
modal.id,
IssueFieldId::Type,
PayloadVariant::IssueType(modal.payload.issue_type),
),
)),
model.ws.as_ref(),
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;
send_ws_msg(
WsMsg::IssueUpdate(
WsMsg::Issue(WsMsgIssue::IssueUpdate(
modal.id,
IssueFieldId::IssueStatusId,
PayloadVariant::I32(modal.payload.issue_status_id),
),
)),
model.ws.as_ref(),
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;
send_ws_msg(
WsMsg::IssueUpdate(
WsMsg::Issue(WsMsgIssue::IssueUpdate(
modal.id,
IssueFieldId::Reporter,
PayloadVariant::I32(modal.payload.reporter_id),
),
)),
model.ws.as_ref(),
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);
send_ws_msg(
WsMsg::IssueUpdate(
WsMsg::Issue(WsMsgIssue::IssueUpdate(
modal.id,
IssueFieldId::Assignees,
PayloadVariant::VecI32(modal.payload.user_ids.clone()),
),
)),
model.ws.as_ref(),
orders,
);
@ -104,11 +105,11 @@ pub fn update(msg: &Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
}
}
send_ws_msg(
WsMsg::IssueUpdate(
WsMsg::Issue(WsMsgIssue::IssueUpdate(
modal.id,
IssueFieldId::Assignees,
PayloadVariant::VecI32(modal.payload.user_ids.clone()),
),
)),
model.ws.as_ref(),
orders,
);
@ -121,11 +122,12 @@ pub fn update(msg: &Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
) => {
modal.payload.priority = (*value).into();
send_ws_msg(
WsMsg::IssueUpdate(
WsMsgIssue::IssueUpdate(
modal.id,
IssueFieldId::Priority,
PayloadVariant::IssuePriority(modal.payload.priority),
),
)
.into(),
model.ws.as_ref(),
orders,
);
@ -138,11 +140,12 @@ pub fn update(msg: &Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
) => {
modal.payload.title = value.clone();
send_ws_msg(
WsMsg::IssueUpdate(
WsMsgIssue::IssueUpdate(
modal.id,
IssueFieldId::Title,
PayloadVariant::String(modal.payload.title.clone()),
),
)
.into(),
model.ws.as_ref(),
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());
send_ws_msg(
WsMsg::IssueUpdate(
WsMsgIssue::IssueUpdate(
modal.id,
IssueFieldId::Description,
PayloadVariant::String(
@ -167,7 +170,8 @@ pub fn update(msg: &Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
.cloned()
.unwrap_or_default(),
),
),
)
.into(),
model.ws.as_ref(),
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();
send_ws_msg(
WsMsg::IssueUpdate(
WsMsgIssue::IssueUpdate(
modal.id,
IssueFieldId::TimeSpent,
PayloadVariant::OptionI32(modal.payload.time_spent),
),
)
.into(),
model.ws.as_ref(),
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);
send_ws_msg(
WsMsg::IssueUpdate(
WsMsgIssue::IssueUpdate(
modal.id,
IssueFieldId::TimeSpent,
PayloadVariant::OptionI32(modal.payload.time_spent),
),
)
.into(),
model.ws.as_ref(),
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();
send_ws_msg(
WsMsg::IssueUpdate(
WsMsgIssue::IssueUpdate(
modal.id,
IssueFieldId::TimeRemaining,
PayloadVariant::OptionI32(modal.payload.time_remaining),
),
)
.into(),
model.ws.as_ref(),
orders,
);
@ -227,11 +234,12 @@ pub fn update(msg: &Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
modal.payload.time_remaining =
modal.time_remaining_select.values.get(0).map(|n| *n as i32);
send_ws_msg(
WsMsg::IssueUpdate(
WsMsgIssue::IssueUpdate(
modal.id,
IssueFieldId::TimeRemaining,
PayloadVariant::OptionI32(modal.payload.time_remaining),
),
)
.into(),
model.ws.as_ref(),
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();
send_ws_msg(
WsMsg::IssueUpdate(
WsMsgIssue::IssueUpdate(
modal.id,
IssueFieldId::Estimate,
PayloadVariant::OptionI32(modal.payload.estimate),
),
)
.into(),
model.ws.as_ref(),
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);
send_ws_msg(
WsMsg::IssueUpdate(
WsMsgIssue::IssueUpdate(
modal.id,
IssueFieldId::Estimate,
PayloadVariant::OptionI32(modal.payload.estimate),
),
)
.into(),
model.ws.as_ref(),
orders,
);
@ -272,11 +282,12 @@ pub fn update(msg: &Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
StyledSelectChanged::Changed(v),
) => {
send_ws_msg(
WsMsg::IssueUpdate(
WsMsgIssue::IssueUpdate(
modal.id,
IssueFieldId::EpicName,
PayloadVariant::OptionI32(v.map(|n| n as EpicId)),
),
)
.into(),
model.ws.as_ref(),
orders,
);
@ -301,17 +312,17 @@ pub fn update(msg: &Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
}
Msg::SaveComment => {
let msg = match modal.comment_form.id {
Some(id) => WsMsg::CommentUpdate(UpdateCommentPayload {
Some(id) => WsMsgComment::CommentUpdate(UpdateCommentPayload {
id,
body: modal.comment_form.body.clone(),
}),
_ => WsMsg::CommentCreate(CreateCommentPayload {
_ => WsMsgComment::CommentCreate(CreateCommentPayload {
user_id: None,
body: modal.comment_form.body.clone(),
issue_id: modal.id,
}),
};
send_ws_msg(msg, model.ws.as_ref(), orders);
send_ws_msg(msg.into(), model.ws.as_ref(), orders);
orders
.skip()
.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;
}
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);
}

View File

@ -1,3 +1,4 @@
use jirs_data::msg::WsMsgComment;
use jirs_data::{CommentId, EpicId, IssueId, IssueStatusId, TimeTracking, WsMsg};
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)
};
send_ws_msg(
WsMsg::IssueCommentsLoad(issue_id),
WsMsg::Comment(WsMsgComment::IssueCommentsLoad(issue_id)),
model.ws.as_ref(),
orders,
);

View File

@ -1,4 +1,4 @@
use jirs_data::WsMsg;
use jirs_data::msg::WsMsgIssueStatus;
use seed::app::Orders;
use crate::model::{Model, Page, PageContent};
@ -39,5 +39,9 @@ fn build_page_content(model: &mut Model, orders: &mut impl Orders<Msg>) {
return;
}
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 jirs_data::fields::*;
use jirs_data::msg::WsMsgInvitation;
use jirs_data::WsMsg;
use seed::prelude::*;
@ -26,10 +27,10 @@ pub fn update(msg: Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
match msg {
Msg::WebSocketChange(WebSocketChanged::WsMsg(ws_msg)) => match ws_msg {
WsMsg::InvitationAcceptFailure(_) => {
WsMsg::Invitation(WsMsgInvitation::InvitationAcceptFailure(_)) => {
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)) {
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)) => {
if let Ok(token) = uuid::Uuid::from_str(page.token.as_str()) {
send_ws_msg(
WsMsg::InvitationAcceptRequest(token),
WsMsgInvitation::InvitationAcceptRequest(token).into(),
model.ws.as_ref(),
orders,
);

View File

@ -1,3 +1,4 @@
use jirs_data::msg::WsMsgIssue;
use jirs_data::*;
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) => {
send_ws_msg(
jirs_data::WsMsg::IssueDelete(issue_id),
jirs_data::WsMsg::Issue(WsMsgIssue::IssueDelete(issue_id)),
model.ws.as_ref(),
orders,
);

View File

@ -1,5 +1,6 @@
use std::collections::HashSet;
use jirs_data::msg::{WsMsgIssueStatus, WsMsgProject};
use jirs_data::{IssueStatus, IssueStatusId, ProjectFieldId, UpdateProjectPayload, WsMsg};
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(..)) => {
board_load(model, orders);
}
WebSocketChanged::WsMsg(WsMsg::IssueStatusCreated(_)) => {
WebSocketChanged::WsMsg(WsMsg::IssueStatus(WsMsgIssueStatus::IssueStatusCreated(
_,
))) => {
match &mut model.page_content {
PageContent::ProjectSettings(page) if Some(0) == page.edit_column_id => {
page.reset();
@ -83,14 +86,15 @@ pub fn update(msg: Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
ProjectPageChange::SubmitProjectSettingsForm,
)) => {
send_ws_msg(
WsMsg::ProjectUpdateLoad(UpdateProjectPayload {
WsMsgProject::ProjectUpdateLoad(UpdateProjectPayload {
id: page.payload.id,
name: page.payload.name.clone(),
url: page.payload.url.clone(),
description: page.payload.description.clone(),
category: page.payload.category,
time_tracking: Some(page.time_tracking.value.into()),
}),
})
.into(),
model.ws.as_ref(),
orders,
);
@ -129,7 +133,7 @@ pub fn update(msg: Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
.map(|is| (is.id, is.position))
{
send_ws_msg(
WsMsg::IssueStatusUpdate(id, name, pos),
WsMsgIssueStatus::IssueStatusUpdate(id, name, pos).into(),
model.ws.as_ref(),
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 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);
}
_ => (),
@ -226,7 +230,7 @@ fn sync(model: &mut Model, orders: &mut impl Orders<Msg>) {
_ => continue,
};
send_ws_msg(
WsMsg::IssueStatusUpdate(id, name.clone(), *position),
WsMsgIssueStatus::IssueStatusUpdate(id, name.clone(), *position).into(),
model.ws.as_ref(),
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)));
}
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 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() => {
invitation_load(model, orders);
}
WebSocketChanged::WsMsg(WsMsg::InvitedUsersLoaded(users)) => {
WebSocketChanged::WsMsg(WsMsg::Invitation(WsMsgInvitation::InvitedUsersLoaded(
users,
))) => {
page.invited_users = users;
}
WebSocketChanged::WsMsg(WsMsg::InvitationListLoaded(invitations)) => {
WebSocketChanged::WsMsg(WsMsg::Invitation(WsMsgInvitation::InvitationListLoaded(
invitations,
))) => {
page.invitations = invitations;
}
WebSocketChanged::WsMsg(WsMsg::InvitationRevokeSuccess(id)) => {
WebSocketChanged::WsMsg(WsMsg::Invitation(
WsMsgInvitation::InvitationRevokeSuccess(id),
)) => {
let mut old = vec![];
std::mem::swap(&mut page.invitations, &mut 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);
}
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![];
std::mem::swap(&mut page.invited_users, &mut 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) => {
send_ws_msg(WsMsg::InvitationListLoad, model.ws.as_ref(), orders);
WebSocketChanged::WsMsg(WsMsg::Invitation(WsMsgInvitation::InvitationSendSuccess)) => {
send_ws_msg(
WsMsgInvitation::InvitationListLoad.into(),
model.ws.as_ref(),
orders,
);
page.form_state = InvitationFormState::Succeed;
}
WebSocketChanged::WsMsg(WsMsg::InvitationSendFailure) => {
WebSocketChanged::WsMsg(WsMsg::Invitation(WsMsgInvitation::InvitationSendFailure)) => {
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;
send_ws_msg(
WsMsg::InvitationSendRequest {
WsMsg::Invitation(WsMsgInvitation::InvitationSendRequest {
name: page.name.clone(),
email: page.email.clone(),
role,
},
}),
model.ws.as_ref(),
orders,
);
}
Msg::InviteRevokeRequest(invitation_id) => {
send_ws_msg(
WsMsg::InvitationRevokeRequest(invitation_id),
WsMsg::Invitation(WsMsgInvitation::InvitationRevokeRequest(invitation_id)),
model.ws.as_ref(),
orders,
);
}
Msg::InvitedUserRemove(user_id) => {
send_ws_msg(
WsMsg::InvitedUserRemoveRequest(user_id),
WsMsg::Invitation(WsMsgInvitation::InvitedUserRemoveRequest(user_id)),
model.ws.as_ref(),
orders,
);

View File

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

View File

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

View File

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

View File

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

View File

@ -1,4 +1,5 @@
pub use init_load_sets::*;
use jirs_data::msg::{WsMsgComment, WsMsgEpic, WsMsgIssue, WsMsgIssueStatus, WsMsgProject};
use jirs_data::*;
use seed::prelude::*;
@ -129,7 +130,7 @@ pub fn update(msg: WsMsg, model: &mut Model, orders: &mut impl Orders<Msg>) {
}
}
// project
WsMsg::ProjectsLoaded(v) => {
WsMsg::Project(WsMsgProject::ProjectsLoaded(v)) => {
model.projects = v;
init_current_project(model, orders);
orders.send_msg(Msg::ResourceChanged(
@ -175,7 +176,7 @@ pub fn update(msg: WsMsg, model: &mut Model, orders: &mut impl Orders<Msg>) {
}
// issue statuses
WsMsg::IssueStatusesLoaded(v) => {
WsMsg::IssueStatus(WsMsgIssueStatus::IssueStatusesLoaded(v)) => {
model.issue_statuses = v;
model
.issue_statuses
@ -186,7 +187,7 @@ pub fn update(msg: WsMsg, model: &mut Model, orders: &mut impl Orders<Msg>) {
None,
));
}
WsMsg::IssueStatusCreated(is) => {
WsMsg::IssueStatus(WsMsgIssueStatus::IssueStatusCreated(is)) => {
let id = is.id;
model.issue_statuses.push(is);
model
@ -198,7 +199,7 @@ pub fn update(msg: WsMsg, model: &mut Model, orders: &mut impl Orders<Msg>) {
Some(id),
));
}
WsMsg::IssueStatusUpdated(mut changed) => {
WsMsg::IssueStatus(WsMsgIssueStatus::IssueStatusUpdated(mut changed)) => {
let 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);
@ -212,7 +213,7 @@ pub fn update(msg: WsMsg, model: &mut Model, orders: &mut impl Orders<Msg>) {
Some(id),
));
}
WsMsg::IssueStatusDeleted(dropped_id, _count) => {
WsMsg::IssueStatus(WsMsgIssueStatus::IssueStatusDeleted(dropped_id, _count)) => {
let mut old = vec![];
std::mem::swap(&mut model.issue_statuses, &mut old);
for is in old {
@ -230,7 +231,7 @@ pub fn update(msg: WsMsg, model: &mut Model, orders: &mut impl Orders<Msg>) {
));
}
// 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)));
{
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,
));
}
WsMsg::IssueUpdated(issue) => {
WsMsg::Issue(WsMsgIssue::IssueUpdated(issue)) => {
let id = issue.id;
model.issues_by_id.remove(&id);
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),
));
}
WsMsg::IssueDeleted(id, _count) => {
WsMsg::Issue(WsMsgIssue::IssueDeleted(id, _count)) => {
let mut old = vec![];
std::mem::swap(model.issues_mut(), &mut old);
for is in old {
@ -275,7 +276,7 @@ pub fn update(msg: WsMsg, model: &mut Model, orders: &mut impl Orders<Msg>) {
));
}
// users
WsMsg::ProjectUsersLoaded(v) => {
WsMsg::Project(WsMsgProject::ProjectUsersLoaded(v)) => {
model.users = v.clone();
model.users_by_id.clear();
for user in v {
@ -288,7 +289,7 @@ pub fn update(msg: WsMsg, model: &mut Model, orders: &mut impl Orders<Msg>) {
));
}
// comments
WsMsg::IssueCommentsLoaded(mut comments) => {
WsMsg::Comment(WsMsgComment::IssueCommentsLoaded(mut comments)) => {
let issue_id = match &model.modals().edit_issue {
Some(modal) => modal.id,
_ => return,
@ -307,7 +308,7 @@ pub fn update(msg: WsMsg, model: &mut Model, orders: &mut impl Orders<Msg>) {
None,
));
}
WsMsg::CommentUpdated(comment) => {
WsMsg::Comment(WsMsgComment::CommentUpdated(comment)) => {
let comment_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());
@ -319,7 +320,7 @@ pub fn update(msg: WsMsg, model: &mut Model, orders: &mut impl Orders<Msg>) {
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) {
model.comments.remove(idx);
}
@ -381,7 +382,7 @@ pub fn update(msg: WsMsg, model: &mut Model, orders: &mut impl Orders<Msg>) {
}
// epics
WsMsg::EpicsLoaded(epics) => {
WsMsg::Epic(WsMsgEpic::EpicsLoaded(epics)) => {
model.epics = epics.clone();
for epic in epics {
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,
));
}
WsMsg::EpicCreated(epic) => {
WsMsg::Epic(WsMsgEpic::EpicCreated(epic)) => {
let id = epic.id;
model.epics.push(epic.clone());
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),
));
}
WsMsg::EpicUpdated(epic) => {
WsMsg::Epic(WsMsgEpic::EpicUpdated(epic)) => {
let epic_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());
@ -416,7 +417,7 @@ pub fn update(msg: WsMsg, model: &mut Model, orders: &mut impl Orders<Msg>) {
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) {
model.epics.remove(idx);
}

View File

@ -23,29 +23,9 @@ actix = { version = "0.10.0" }
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_json = { version = ">=0.8.0, <2.0" }
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 = "*" }
openssl-sys = { version = "*", features = ["vendored"] }

View File

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