From c0ab2636d699c8544ce03a58f61b95cfd66ff7ce Mon Sep 17 00:00:00 2001 From: Joram Wilander Date: Mon, 18 Jul 2016 11:10:03 -0400 Subject: PLT-2241 Refactored statuses into a more real-time system (#3573) * Refactored statuses into a more real-time system * Updated package.json with correct commit and fixed minor bug * Minor updates to statuses based on feedback * When setting status online, update only LastActivityAt if status already exists --- model/client.go | 5 +++-- model/config.go | 6 ++++++ model/status.go | 42 ++++++++++++++++++++++++++++++++++++++++++ model/status_test.go | 27 +++++++++++++++++++++++++++ model/user.go | 16 ---------------- model/websocket_client.go | 7 +++++++ 6 files changed, 85 insertions(+), 18 deletions(-) create mode 100644 model/status.go create mode 100644 model/status_test.go (limited to 'model') diff --git a/model/client.go b/model/client.go index e12cd595d..b97a2f7ad 100644 --- a/model/client.go +++ b/model/client.go @@ -1415,8 +1415,9 @@ func (c *Client) AdminResetPassword(userId, newPassword string) (*Result, *AppEr } } -func (c *Client) GetStatuses(data []string) (*Result, *AppError) { - if r, err := c.DoApiPost("/users/status", ArrayToJson(data)); err != nil { +// GetStatuses returns a map of string statuses using user id as the key +func (c *Client) GetStatuses() (*Result, *AppError) { + if r, err := c.DoApiGet("/users/status", "", ""); err != nil { return nil, err } else { defer closeBody(r) diff --git a/model/config.go b/model/config.go index 532584a1a..4767378fb 100644 --- a/model/config.go +++ b/model/config.go @@ -195,6 +195,7 @@ type TeamSettings struct { RestrictTeamInvite *string RestrictPublicChannelManagement *string RestrictPrivateChannelManagement *string + UserStatusAwayTimeout *int64 } type LdapSettings struct { @@ -435,6 +436,11 @@ func (o *Config) SetDefaults() { *o.TeamSettings.RestrictPrivateChannelManagement = PERMISSIONS_ALL } + if o.TeamSettings.UserStatusAwayTimeout == nil { + o.TeamSettings.UserStatusAwayTimeout = new(int64) + *o.TeamSettings.UserStatusAwayTimeout = 300 + } + if o.EmailSettings.EnableSignInWithEmail == nil { o.EmailSettings.EnableSignInWithEmail = new(bool) diff --git a/model/status.go b/model/status.go new file mode 100644 index 000000000..8bf26f2f0 --- /dev/null +++ b/model/status.go @@ -0,0 +1,42 @@ +// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. +// See License.txt for license information. + +package model + +import ( + "encoding/json" + "io" +) + +const ( + STATUS_OFFLINE = "offline" + STATUS_AWAY = "away" + STATUS_ONLINE = "online" + STATUS_CACHE_SIZE = 10000 +) + +type Status struct { + UserId string `json:"user_id"` + Status string `json:"status"` + LastActivityAt int64 `json:"last_activity_at"` +} + +func (o *Status) ToJson() string { + b, err := json.Marshal(o) + if err != nil { + return "" + } else { + return string(b) + } +} + +func StatusFromJson(data io.Reader) *Status { + decoder := json.NewDecoder(data) + var o Status + err := decoder.Decode(&o) + if err == nil { + return &o + } else { + return nil + } +} diff --git a/model/status_test.go b/model/status_test.go new file mode 100644 index 000000000..ccdac53b6 --- /dev/null +++ b/model/status_test.go @@ -0,0 +1,27 @@ +// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. +// See License.txt for license information. + +package model + +import ( + "strings" + "testing" +) + +func TestStatus(t *testing.T) { + status := Status{NewId(), STATUS_ONLINE, 0} + json := status.ToJson() + status2 := StatusFromJson(strings.NewReader(json)) + + if status.UserId != status2.UserId { + t.Fatal("UserId should have matched") + } + + if status.Status != status2.Status { + t.Fatal("Status should have matched") + } + + if status.LastActivityAt != status2.LastActivityAt { + t.Fatal("LastActivityAt should have matched") + } +} diff --git a/model/user.go b/model/user.go index bf6866b27..2a7427748 100644 --- a/model/user.go +++ b/model/user.go @@ -16,11 +16,6 @@ import ( const ( ROLE_SYSTEM_ADMIN = "system_admin" - USER_AWAY_TIMEOUT = 5 * 60 * 1000 // 5 minutes - USER_OFFLINE_TIMEOUT = 1 * 60 * 1000 // 1 minute - USER_OFFLINE = "offline" - USER_AWAY = "away" - USER_ONLINE = "online" USER_NOTIFY_ALL = "all" USER_NOTIFY_MENTION = "mention" USER_NOTIFY_NONE = "none" @@ -44,8 +39,6 @@ type User struct { FirstName string `json:"first_name"` LastName string `json:"last_name"` Roles string `json:"roles"` - LastActivityAt int64 `json:"last_activity_at,omitempty"` - LastPingAt int64 `json:"last_ping_at,omitempty"` AllowMarketing bool `json:"allow_marketing,omitempty"` Props StringMap `json:"props,omitempty"` NotifyProps StringMap `json:"notify_props,omitempty"` @@ -222,14 +215,6 @@ func (u *User) Etag(showFullName, showEmail bool) string { return Etag(u.Id, u.UpdateAt, showFullName, showEmail) } -func (u *User) IsOffline() bool { - return (GetMillis()-u.LastPingAt) > USER_OFFLINE_TIMEOUT && (GetMillis()-u.LastActivityAt) > USER_OFFLINE_TIMEOUT -} - -func (u *User) IsAway() bool { - return (GetMillis() - u.LastActivityAt) > USER_AWAY_TIMEOUT -} - // Remove any private data from the user object func (u *User) Sanitize(options map[string]bool) { u.Password = "" @@ -258,7 +243,6 @@ func (u *User) ClearNonProfileFields() { u.MfaActive = false u.MfaSecret = "" u.EmailVerified = false - u.LastPingAt = 0 u.AllowMarketing = false u.Props = StringMap{} u.NotifyProps = StringMap{} diff --git a/model/websocket_client.go b/model/websocket_client.go index 7b9dc0b50..a048bd855 100644 --- a/model/websocket_client.go +++ b/model/websocket_client.go @@ -92,6 +92,8 @@ func (wsc *WebSocketClient) SendMessage(action string, data map[string]interface wsc.Conn.WriteJSON(req) } +// UserTyping will push a user_typing event out to all connected users +// who are in the specified channel func (wsc *WebSocketClient) UserTyping(channelId, parentId string) { data := map[string]interface{}{ "channel_id": channelId, @@ -100,3 +102,8 @@ func (wsc *WebSocketClient) UserTyping(channelId, parentId string) { wsc.SendMessage("user_typing", data) } + +// GetStatuses will return a map of string statuses using user id as the key +func (wsc *WebSocketClient) GetStatuses() { + wsc.SendMessage("get_statuses", nil) +} -- cgit v1.2.3-1-g7c22