Commit 1a0f8d1b authored by Harrison Healey's avatar Harrison Healey Committed by George Goldberg

PLT-1384 Added websocket event when preferences are updated/deleted (#6107)

parent b79439e9
......@@ -40,18 +40,8 @@ func savePreferences(c *Context, w http.ResponseWriter, r *http.Request) {
return
}
for _, preference := range preferences {
if c.Session.UserId != preference.UserId {
c.Err = model.NewLocAppError("savePreferences", "api.preference.save_preferences.set.app_error", nil,
c.T("api.preference.save_preferences.set_details.app_error",
map[string]interface{}{"SessionUserId": c.Session.UserId, "PreferenceUserId": preference.UserId}))
c.Err.StatusCode = http.StatusForbidden
return
}
}
if result := <-app.Srv.Store.Preference().Save(&preferences); result.Err != nil {
c.Err = result.Err
if err := app.UpdatePreferences(c.Session.UserId, preferences); err != nil {
c.Err = err
return
}
......@@ -92,20 +82,9 @@ func deletePreferences(c *Context, w http.ResponseWriter, r *http.Request) {
return
}
for _, preference := range preferences {
if c.Session.UserId != preference.UserId {
c.Err = model.NewLocAppError("deletePreferences", "api.preference.delete_preferences.user_id.app_error",
nil, "session.user_id="+c.Session.UserId+",preference.user_id="+preference.UserId)
c.Err.StatusCode = http.StatusForbidden
return
}
}
for _, preference := range preferences {
if result := <-app.Srv.Store.Preference().Delete(c.Session.UserId, preference.Category, preference.Name); result.Err != nil {
c.Err = result.Err
return
}
if err := app.DeletePreferences(c.Session.UserId, preferences); err != nil {
c.Err = err
return
}
ReturnStatusOK(w)
......
......@@ -76,7 +76,7 @@ type Routes struct {
System *mux.Router // 'api/v4/system'
Preferences *mux.Router // 'api/v4/preferences'
Preferences *mux.Router // 'api/v4/users/{user_id:[A-Za-z0-9]+}/preferences'
License *mux.Router // 'api/v4/license'
......
......@@ -99,17 +99,7 @@ func updatePreferences(c *Context, w http.ResponseWriter, r *http.Request) {
return
}
for _, preference := range preferences {
if c.Params.UserId != preference.UserId {
c.Err = model.NewAppError("savePreferences", "api.preference.update_preferences.set.app_error", nil,
c.T("api.preference.update_preferences.set_details.app_error",
map[string]interface{}{"SessionUserId": c.Params.UserId, "PreferenceUserId": preference.UserId}),
http.StatusForbidden)
return
}
}
if _, err := app.UpdatePreferences(preferences); err != nil {
if err := app.UpdatePreferences(c.Params.UserId, preferences); err != nil {
c.Err = err
return
}
......@@ -134,17 +124,7 @@ func deletePreferences(c *Context, w http.ResponseWriter, r *http.Request) {
return
}
for _, preference := range preferences {
if c.Params.UserId != preference.UserId {
c.Err = model.NewAppError("deletePreferences", "api.preference.delete_preferences.delete.app_error", nil,
c.T("api.preference.delete_preferences.delete.app_error",
map[string]interface{}{"SessionUserId": c.Params.UserId, "PreferenceUserId": preference.UserId}),
http.StatusForbidden)
return
}
}
if _, err := app.DeletePreferences(c.Params.UserId, preferences); err != nil {
if err := app.DeletePreferences(c.Params.UserId, preferences); err != nil {
c.Err = err
return
}
......
......@@ -4,8 +4,11 @@
package api4
import (
"github.com/mattermost/platform/model"
"strings"
"testing"
"time"
"github.com/mattermost/platform/model"
)
func TestGetPreferences(t *testing.T) {
......@@ -239,6 +242,61 @@ func TestUpdatePreferences(t *testing.T) {
CheckUnauthorizedStatus(t, resp)
}
func TestUpdatePreferencesWebsocket(t *testing.T) {
th := Setup().InitBasic()
WebSocketClient, err := th.CreateWebSocketClient()
if err != nil {
t.Fatal(err)
}
WebSocketClient.Listen()
userId := th.BasicUser.Id
preferences := &model.Preferences{
{
UserId: userId,
Category: model.NewId(),
Name: model.NewId(),
},
{
UserId: userId,
Category: model.NewId(),
Name: model.NewId(),
},
}
_, resp := th.Client.UpdatePreferences(userId, preferences)
CheckNoError(t, resp)
timeout := time.After(300 * time.Millisecond)
waiting := true
for waiting {
select {
case event := <-WebSocketClient.EventChannel:
if event.Event != model.WEBSOCKET_EVENT_PREFERENCES_CHANGED {
// Ignore any other events
continue
}
received, err := model.PreferencesFromJson(strings.NewReader(event.Data["preferences"].(string)))
if err != nil {
t.Fatal(err)
}
for i, preference := range *preferences {
if preference.UserId != received[i].UserId || preference.Category != received[i].Category || preference.Name != received[i].Name {
t.Fatal("received incorrect preference")
}
}
waiting = false
case <-timeout:
t.Fatal("timed out waiting for preference update event")
}
}
}
func TestDeletePreferences(t *testing.T) {
th := Setup().InitBasic()
defer TearDown()
......@@ -285,3 +343,61 @@ func TestDeletePreferences(t *testing.T) {
_, resp = Client.DeletePreferences(th.BasicUser.Id, &preferences)
CheckUnauthorizedStatus(t, resp)
}
func TestDeletePreferencesWebsocket(t *testing.T) {
th := Setup().InitBasic()
userId := th.BasicUser.Id
preferences := &model.Preferences{
{
UserId: userId,
Category: model.NewId(),
Name: model.NewId(),
},
{
UserId: userId,
Category: model.NewId(),
Name: model.NewId(),
},
}
_, resp := th.Client.UpdatePreferences(userId, preferences)
CheckNoError(t, resp)
WebSocketClient, err := th.CreateWebSocketClient()
if err != nil {
t.Fatal(err)
}
WebSocketClient.Listen()
_, resp = th.Client.DeletePreferences(userId, preferences)
CheckNoError(t, resp)
timeout := time.After(30000 * time.Millisecond)
waiting := true
for waiting {
select {
case event := <-WebSocketClient.EventChannel:
if event.Event != model.WEBSOCKET_EVENT_PREFERENCES_DELETED {
// Ignore any other events
continue
}
received, err := model.PreferencesFromJson(strings.NewReader(event.Data["preferences"].(string)))
if err != nil {
t.Fatal(err)
}
for i, preference := range *preferences {
if preference.UserId != received[i].UserId || preference.Category != received[i].Category || preference.Name != received[i].Name {
t.Fatal("received incorrect preference")
}
}
waiting = false
case <-timeout:
t.Fatal("timed out waiting for preference delete event")
}
}
}
......@@ -39,22 +39,45 @@ func GetPreferenceByCategoryAndNameForUser(userId string, category string, prefe
}
}
func UpdatePreferences(preferences model.Preferences) (bool, *model.AppError) {
func UpdatePreferences(userId string, preferences model.Preferences) *model.AppError {
for _, preference := range preferences {
if userId != preference.UserId {
return model.NewAppError("savePreferences", "api.preference.update_preferences.set.app_error", nil,
"userId="+userId+", preference.UserId="+preference.UserId, http.StatusForbidden)
}
}
if result := <-Srv.Store.Preference().Save(&preferences); result.Err != nil {
result.Err.StatusCode = http.StatusBadRequest
return false, result.Err
return result.Err
}
return true, nil
message := model.NewWebSocketEvent(model.WEBSOCKET_EVENT_PREFERENCES_CHANGED, "", "", userId, nil)
message.Add("preferences", preferences.ToJson())
go Publish(message)
return nil
}
func DeletePreferences(userId string, preferences model.Preferences) (bool, *model.AppError) {
func DeletePreferences(userId string, preferences model.Preferences) *model.AppError {
for _, preference := range preferences {
if userId != preference.UserId {
err := model.NewAppError("deletePreferences", "api.preference.delete_preferences.delete.app_error", nil,
"userId="+userId+", preference.UserId="+preference.UserId, http.StatusForbidden)
return err
}
}
for _, preference := range preferences {
if result := <-Srv.Store.Preference().Delete(userId, preference.Category, preference.Name); result.Err != nil {
result.Err.StatusCode = http.StatusBadRequest
return false, result.Err
return result.Err
}
}
return true, nil
message := model.NewWebSocketEvent(model.WEBSOCKET_EVENT_PREFERENCES_DELETED, "", "", userId, nil)
message.Add("preferences", preferences.ToJson())
go Publish(message)
return nil
}
......@@ -1687,10 +1687,6 @@
"id": "api.preference.save_preferences.set.app_error",
"translation": "Unable to set preferences for other user"
},
{
"id": "api.preference.save_preferences.set_details.app_error",
"translation": "session.user_id={{.SessionUserId}}, preference.user_id={{.PreferenceUserId}}"
},
{
"id": "api.reaction.delete_reaction.mismatched_channel_id.app_error",
"translation": "Failed to delete reaction because channel ID does not match post ID in the URL"
......
......@@ -9,29 +9,31 @@ import (
)
const (
WEBSOCKET_EVENT_TYPING = "typing"
WEBSOCKET_EVENT_POSTED = "posted"
WEBSOCKET_EVENT_POST_EDITED = "post_edited"
WEBSOCKET_EVENT_POST_DELETED = "post_deleted"
WEBSOCKET_EVENT_CHANNEL_DELETED = "channel_deleted"
WEBSOCKET_EVENT_CHANNEL_CREATED = "channel_created"
WEBSOCKET_EVENT_DIRECT_ADDED = "direct_added"
WEBSOCKET_EVENT_GROUP_ADDED = "group_added"
WEBSOCKET_EVENT_NEW_USER = "new_user"
WEBSOCKET_EVENT_ADDED_TO_TEAM = "added_to_team"
WEBSOCKET_EVENT_LEAVE_TEAM = "leave_team"
WEBSOCKET_EVENT_UPDATE_TEAM = "update_team"
WEBSOCKET_EVENT_USER_ADDED = "user_added"
WEBSOCKET_EVENT_USER_UPDATED = "user_updated"
WEBSOCKET_EVENT_USER_REMOVED = "user_removed"
WEBSOCKET_EVENT_PREFERENCE_CHANGED = "preference_changed"
WEBSOCKET_EVENT_EPHEMERAL_MESSAGE = "ephemeral_message"
WEBSOCKET_EVENT_STATUS_CHANGE = "status_change"
WEBSOCKET_EVENT_HELLO = "hello"
WEBSOCKET_EVENT_WEBRTC = "webrtc"
WEBSOCKET_AUTHENTICATION_CHALLENGE = "authentication_challenge"
WEBSOCKET_EVENT_REACTION_ADDED = "reaction_added"
WEBSOCKET_EVENT_REACTION_REMOVED = "reaction_removed"
WEBSOCKET_EVENT_TYPING = "typing"
WEBSOCKET_EVENT_POSTED = "posted"
WEBSOCKET_EVENT_POST_EDITED = "post_edited"
WEBSOCKET_EVENT_POST_DELETED = "post_deleted"
WEBSOCKET_EVENT_CHANNEL_DELETED = "channel_deleted"
WEBSOCKET_EVENT_CHANNEL_CREATED = "channel_created"
WEBSOCKET_EVENT_DIRECT_ADDED = "direct_added"
WEBSOCKET_EVENT_GROUP_ADDED = "group_added"
WEBSOCKET_EVENT_NEW_USER = "new_user"
WEBSOCKET_EVENT_ADDED_TO_TEAM = "added_to_team"
WEBSOCKET_EVENT_LEAVE_TEAM = "leave_team"
WEBSOCKET_EVENT_UPDATE_TEAM = "update_team"
WEBSOCKET_EVENT_USER_ADDED = "user_added"
WEBSOCKET_EVENT_USER_UPDATED = "user_updated"
WEBSOCKET_EVENT_USER_REMOVED = "user_removed"
WEBSOCKET_EVENT_PREFERENCE_CHANGED = "preference_changed"
WEBSOCKET_EVENT_PREFERENCES_CHANGED = "preferences_changed"
WEBSOCKET_EVENT_PREFERENCES_DELETED = "preferences_deleted"
WEBSOCKET_EVENT_EPHEMERAL_MESSAGE = "ephemeral_message"
WEBSOCKET_EVENT_STATUS_CHANGE = "status_change"
WEBSOCKET_EVENT_HELLO = "hello"
WEBSOCKET_EVENT_WEBRTC = "webrtc"
WEBSOCKET_AUTHENTICATION_CHALLENGE = "authentication_challenge"
WEBSOCKET_EVENT_REACTION_ADDED = "reaction_added"
WEBSOCKET_EVENT_REACTION_REMOVED = "reaction_removed"
)
type WebSocketMessage interface {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment