diff options
-rw-r--r-- | app/channel.go | 12 | ||||
-rw-r--r-- | app/channel_test.go | 41 | ||||
-rw-r--r-- | app/plugin_api.go | 25 | ||||
-rw-r--r-- | plugin/api.go | 12 | ||||
-rw-r--r-- | plugin/plugintest/api.go | 39 | ||||
-rw-r--r-- | plugin/rpcplugin/api.go | 103 | ||||
-rw-r--r-- | plugin/rpcplugin/api_test.go | 23 |
7 files changed, 250 insertions, 5 deletions
diff --git a/app/channel.go b/app/channel.go index 6e11d4e5d..40f21c3a9 100644 --- a/app/channel.go +++ b/app/channel.go @@ -652,8 +652,10 @@ func (a *App) AddChannelMember(userId string, channel *model.Channel, userReques } var userRequestor *model.User - if userRequestor, err = a.GetUser(userRequestorId); err != nil { - return nil, err + if userRequestorId != "" { + if userRequestor, err = a.GetUser(userRequestorId); err != nil { + return nil, err + } } cm, err := a.AddUserToChannel(user, channel) @@ -661,7 +663,7 @@ func (a *App) AddChannelMember(userId string, channel *model.Channel, userReques return nil, err } - if userId == userRequestorId { + if userRequestorId == "" || userId == userRequestorId { a.postJoinChannelMessage(user, channel) } else { a.Go(func() { @@ -669,7 +671,9 @@ func (a *App) AddChannelMember(userId string, channel *model.Channel, userReques }) } - a.UpdateChannelLastViewedAt([]string{channel.Id}, userRequestor.Id) + if userRequestor != nil { + a.UpdateChannelLastViewedAt([]string{channel.Id}, userRequestor.Id) + } return cm, nil } diff --git a/app/channel_test.go b/app/channel_test.go index 69efaeca7..a4e0806a6 100644 --- a/app/channel_test.go +++ b/app/channel_test.go @@ -340,3 +340,44 @@ func TestRemoveUserFromChannelUpdatesChannelMemberHistoryRecord(t *testing.T) { assert.Equal(t, publicChannel.Id, histories[0].ChannelId) assert.NotNil(t, histories[0].LeaveTime) } + +func TestAddChannelMemberNoUserRequestor(t *testing.T) { + th := Setup().InitBasic() + defer th.TearDown() + + // create a user and add it to a channel + user := th.CreateUser() + if _, err := th.App.AddTeamMember(th.BasicTeam.Id, user.Id); err != nil { + t.Fatal("Failed to add user to team. Error: " + err.Message) + } + + groupUserIds := make([]string, 0) + groupUserIds = append(groupUserIds, th.BasicUser.Id) + groupUserIds = append(groupUserIds, user.Id) + + channel := th.createChannel(th.BasicTeam, model.CHANNEL_OPEN) + userRequestorId := "" + postRootId := "" + if _, err := th.App.AddChannelMember(user.Id, channel, userRequestorId, postRootId); err != nil { + t.Fatal("Failed to add user to channel. Error: " + err.Message) + } + + // there should be a ChannelMemberHistory record for the user + histories := store.Must(th.App.Srv.Store.ChannelMemberHistory().GetUsersInChannelDuring(model.GetMillis()-100, model.GetMillis()+100, channel.Id)).([]*model.ChannelMemberHistoryResult) + assert.Len(t, histories, 2) + channelMemberHistoryUserIds := make([]string, 0) + for _, history := range histories { + assert.Equal(t, channel.Id, history.ChannelId) + channelMemberHistoryUserIds = append(channelMemberHistoryUserIds, history.UserId) + } + assert.Equal(t, groupUserIds, channelMemberHistoryUserIds) + + postList := store.Must(th.App.Srv.Store.Post().GetPosts(channel.Id, 0, 1, false)).(*model.PostList) + if assert.Len(t, postList.Order, 1) { + post := postList.Posts[postList.Order[0]] + + assert.Equal(t, model.POST_JOIN_CHANNEL, post.Type) + assert.Equal(t, user.Id, post.UserId) + assert.Equal(t, user.Username, post.Props["username"]) + } +} diff --git a/app/plugin_api.go b/app/plugin_api.go index 21b828368..b09a0c419 100644 --- a/app/plugin_api.go +++ b/app/plugin_api.go @@ -124,10 +124,35 @@ func (api *PluginAPI) UpdateChannel(channel *model.Channel) (*model.Channel, *mo return api.app.UpdateChannel(channel) } +func (api *PluginAPI) AddChannelMember(channelId, userId string) (*model.ChannelMember, *model.AppError) { + // For now, don't allow overriding these via the plugin API. + userRequestorId := "" + postRootId := "" + + channel, err := api.GetChannel(channelId) + if err != nil { + return nil, err + } + + return api.app.AddChannelMember(userId, channel, userRequestorId, postRootId) +} + func (api *PluginAPI) GetChannelMember(channelId, userId string) (*model.ChannelMember, *model.AppError) { return api.app.GetChannelMember(channelId, userId) } +func (api *PluginAPI) UpdateChannelMemberRoles(channelId, userId, newRoles string) (*model.ChannelMember, *model.AppError) { + return api.app.UpdateChannelMemberRoles(channelId, userId, newRoles) +} + +func (api *PluginAPI) UpdateChannelMemberNotifications(channelId, userId string, notifications map[string]string) (*model.ChannelMember, *model.AppError) { + return api.app.UpdateChannelMemberNotifyProps(notifications, channelId, userId) +} + +func (api *PluginAPI) DeleteChannelMember(channelId, userId string) *model.AppError { + return api.app.LeaveChannel(channelId, userId) +} + func (api *PluginAPI) CreatePost(post *model.Post) (*model.Post, *model.AppError) { return api.app.CreatePostMissingChannel(post, true) } diff --git a/plugin/api.go b/plugin/api.go index 437188f6e..d62c2f069 100644 --- a/plugin/api.go +++ b/plugin/api.go @@ -77,9 +77,21 @@ type API interface { // UpdateChannel updates a channel. UpdateChannel(channel *model.Channel) (*model.Channel, *model.AppError) + // AddChannelMember creates a channel membership for a user. + AddChannelMember(channelId, userId string) (*model.ChannelMember, *model.AppError) + // GetChannelMember gets a channel membership for a user. GetChannelMember(channelId, userId string) (*model.ChannelMember, *model.AppError) + // UpdateChannelMemberRoles updates a user's roles for a channel. + UpdateChannelMemberRoles(channelId, userId, newRoles string) (*model.ChannelMember, *model.AppError) + + // UpdateChannelMemberNotifications updates a user's notification properties for a channel. + UpdateChannelMemberNotifications(channelId, userId string, notifications map[string]string) (*model.ChannelMember, *model.AppError) + + // DeleteChannelMember deletes a channel membership for a user. + DeleteChannelMember(channelId, userId string) *model.AppError + // CreatePost creates a post. CreatePost(post *model.Post) (*model.Post, *model.AppError) diff --git a/plugin/plugintest/api.go b/plugin/plugintest/api.go index 75174a9a6..8f9f4a604 100644 --- a/plugin/plugintest/api.go +++ b/plugin/plugintest/api.go @@ -223,6 +223,16 @@ func (m *API) UpdateChannel(channel *model.Channel) (*model.Channel, *model.AppE return channelOut, err } +func (m *API) AddChannelMember(channelId, userId string) (*model.ChannelMember, *model.AppError) { + ret := m.Called(channelId, userId) + if f, ok := ret.Get(0).(func(_, _ string) (*model.ChannelMember, *model.AppError)); ok { + return f(channelId, userId) + } + member, _ := ret.Get(0).(*model.ChannelMember) + err, _ := ret.Get(1).(*model.AppError) + return member, err +} + func (m *API) GetChannelMember(channelId, userId string) (*model.ChannelMember, *model.AppError) { ret := m.Called(channelId, userId) if f, ok := ret.Get(0).(func(_, _ string) (*model.ChannelMember, *model.AppError)); ok { @@ -233,6 +243,35 @@ func (m *API) GetChannelMember(channelId, userId string) (*model.ChannelMember, return member, err } +func (m *API) UpdateChannelMemberRoles(channelId, userId, newRoles string) (*model.ChannelMember, *model.AppError) { + ret := m.Called(channelId, userId, newRoles) + if f, ok := ret.Get(0).(func(_, _, _ string) (*model.ChannelMember, *model.AppError)); ok { + return f(channelId, userId, newRoles) + } + member, _ := ret.Get(0).(*model.ChannelMember) + err, _ := ret.Get(1).(*model.AppError) + return member, err +} + +func (m *API) UpdateChannelMemberNotifications(channelId, userId string, notifications map[string]string) (*model.ChannelMember, *model.AppError) { + ret := m.Called(channelId, userId, notifications) + if f, ok := ret.Get(0).(func(_, _ string, _ map[string]string) (*model.ChannelMember, *model.AppError)); ok { + return f(channelId, userId, notifications) + } + member, _ := ret.Get(0).(*model.ChannelMember) + err, _ := ret.Get(1).(*model.AppError) + return member, err +} + +func (m *API) DeleteChannelMember(channelId, userId string) *model.AppError { + ret := m.Called(channelId, userId) + if f, ok := ret.Get(0).(func(_, _ string) *model.AppError); ok { + return f(channelId, userId) + } + err, _ := ret.Get(0).(*model.AppError) + return err +} + func (m *API) CreatePost(post *model.Post) (*model.Post, *model.AppError) { ret := m.Called(post) if f, ok := ret.Get(0).(func(*model.Post) (*model.Post, *model.AppError)); ok { diff --git a/plugin/rpcplugin/api.go b/plugin/rpcplugin/api.go index d87f65b55..c81bbb7c5 100644 --- a/plugin/rpcplugin/api.go +++ b/plugin/rpcplugin/api.go @@ -163,11 +163,33 @@ type APIGetGroupChannelArgs struct { UserIds []string } +type APIAddChannelMemberArgs struct { + ChannelId string + UserId string +} + type APIGetChannelMemberArgs struct { ChannelId string UserId string } +type APIUpdateChannelMemberRolesArgs struct { + ChannelId string + UserId string + NewRoles string +} + +type APIUpdateChannelMemberNotificationsArgs struct { + ChannelId string + UserId string + Notifications map[string]string +} + +type APIDeleteChannelMemberArgs struct { + ChannelId string + UserId string +} + type APIChannelReply struct { Channel *model.Channel Error *model.AppError @@ -239,6 +261,15 @@ func (api *LocalAPI) UpdateChannel(args *model.Channel, reply *APIChannelReply) return nil } +func (api *LocalAPI) AddChannelMember(args *APIAddChannelMemberArgs, reply *APIChannelMemberReply) error { + member, err := api.api.AddChannelMember(args.ChannelId, args.UserId) + *reply = APIChannelMemberReply{ + ChannelMember: member, + Error: err, + } + return nil +} + func (api *LocalAPI) GetChannelMember(args *APIGetChannelMemberArgs, reply *APIChannelMemberReply) error { member, err := api.api.GetChannelMember(args.ChannelId, args.UserId) *reply = APIChannelMemberReply{ @@ -248,6 +279,32 @@ func (api *LocalAPI) GetChannelMember(args *APIGetChannelMemberArgs, reply *APIC return nil } +func (api *LocalAPI) UpdateChannelMemberRoles(args *APIUpdateChannelMemberRolesArgs, reply *APIChannelMemberReply) error { + member, err := api.api.UpdateChannelMemberRoles(args.ChannelId, args.UserId, args.NewRoles) + *reply = APIChannelMemberReply{ + ChannelMember: member, + Error: err, + } + return nil +} + +func (api *LocalAPI) UpdateChannelMemberNotifications(args *APIUpdateChannelMemberNotificationsArgs, reply *APIChannelMemberReply) error { + member, err := api.api.UpdateChannelMemberNotifications(args.ChannelId, args.UserId, args.Notifications) + *reply = APIChannelMemberReply{ + ChannelMember: member, + Error: err, + } + return nil +} + +func (api *LocalAPI) DeleteChannelMember(args *APIDeleteChannelMemberArgs, reply *APIErrorReply) error { + err := api.api.DeleteChannelMember(args.ChannelId, args.UserId) + *reply = APIErrorReply{ + Error: err, + } + return nil +} + type APIPostReply struct { Post *model.Post Error *model.AppError @@ -520,6 +577,17 @@ func (api *RemoteAPI) UpdateChannel(channel *model.Channel) (*model.Channel, *mo return reply.Channel, reply.Error } +func (api *RemoteAPI) AddChannelMember(channelId, userId string) (*model.ChannelMember, *model.AppError) { + var reply APIChannelMemberReply + if err := api.client.Call("LocalAPI.AddChannelMember", &APIAddChannelMemberArgs{ + ChannelId: channelId, + UserId: userId, + }, &reply); err != nil { + return nil, model.NewAppError("RemoteAPI.AddChannelMember", "plugin.rpcplugin.invocation.error", nil, "err="+err.Error(), http.StatusInternalServerError) + } + return reply.ChannelMember, reply.Error +} + func (api *RemoteAPI) GetChannelMember(channelId, userId string) (*model.ChannelMember, *model.AppError) { var reply APIChannelMemberReply if err := api.client.Call("LocalAPI.GetChannelMember", &APIGetChannelMemberArgs{ @@ -531,6 +599,41 @@ func (api *RemoteAPI) GetChannelMember(channelId, userId string) (*model.Channel return reply.ChannelMember, reply.Error } +func (api *RemoteAPI) UpdateChannelMemberRoles(channelId, userId, newRoles string) (*model.ChannelMember, *model.AppError) { + var reply APIChannelMemberReply + if err := api.client.Call("LocalAPI.UpdateChannelMemberRoles", &APIUpdateChannelMemberRolesArgs{ + ChannelId: channelId, + UserId: userId, + NewRoles: newRoles, + }, &reply); err != nil { + return nil, model.NewAppError("RemoteAPI.UpdateChannelMemberRoles", "plugin.rpcplugin.invocation.error", nil, "err="+err.Error(), http.StatusInternalServerError) + } + return reply.ChannelMember, reply.Error +} + +func (api *RemoteAPI) UpdateChannelMemberNotifications(channelId, userId string, notifications map[string]string) (*model.ChannelMember, *model.AppError) { + var reply APIChannelMemberReply + if err := api.client.Call("LocalAPI.UpdateChannelMemberNotifications", &APIUpdateChannelMemberNotificationsArgs{ + ChannelId: channelId, + UserId: userId, + Notifications: notifications, + }, &reply); err != nil { + return nil, model.NewAppError("RemoteAPI.UpdateChannelMemberNotifications", "plugin.rpcplugin.invocation.error", nil, "err="+err.Error(), http.StatusInternalServerError) + } + return reply.ChannelMember, reply.Error +} + +func (api *RemoteAPI) DeleteChannelMember(channelId, userId string) *model.AppError { + var reply APIErrorReply + if err := api.client.Call("LocalAPI.DeleteChannelMember", &APIDeleteChannelMemberArgs{ + ChannelId: channelId, + UserId: userId, + }, &reply); err != nil { + return model.NewAppError("RemoteAPI.DeleteChannelMember", "plugin.rpcplugin.invocation.error", nil, "err="+err.Error(), http.StatusInternalServerError) + } + return reply.Error +} + func (api *RemoteAPI) CreatePost(post *model.Post) (*model.Post, *model.AppError) { var reply APIPostReply if err := api.client.Call("LocalAPI.CreatePost", post, &reply); err != nil { diff --git a/plugin/rpcplugin/api_test.go b/plugin/rpcplugin/api_test.go index 7fe7a0ff9..d7b3733ea 100644 --- a/plugin/rpcplugin/api_test.go +++ b/plugin/rpcplugin/api_test.go @@ -128,11 +128,32 @@ func TestAPI(t *testing.T) { assert.Equal(t, testChannel, channel) assert.Nil(t, err) + api.On("AddChannelMember", testChannel.Id, "theuserid").Return(testChannelMember, nil).Once() + member, err := remote.AddChannelMember(testChannel.Id, "theuserid") + assert.Equal(t, testChannelMember, member) + assert.Nil(t, err) + api.On("GetChannelMember", "thechannelid", "theuserid").Return(testChannelMember, nil).Once() - member, err := remote.GetChannelMember("thechannelid", "theuserid") + member, err = remote.GetChannelMember("thechannelid", "theuserid") + assert.Equal(t, testChannelMember, member) + assert.Nil(t, err) + + api.On("UpdateChannelMemberRoles", testChannel.Id, "theuserid", model.CHANNEL_ADMIN_ROLE_ID).Return(testChannelMember, nil).Once() + member, err = remote.UpdateChannelMemberRoles(testChannel.Id, "theuserid", model.CHANNEL_ADMIN_ROLE_ID) assert.Equal(t, testChannelMember, member) assert.Nil(t, err) + notifications := map[string]string{} + notifications[model.MARK_UNREAD_NOTIFY_PROP] = model.CHANNEL_MARK_UNREAD_MENTION + api.On("UpdateChannelMemberNotifications", testChannel.Id, "theuserid", notifications).Return(testChannelMember, nil).Once() + member, err = remote.UpdateChannelMemberNotifications(testChannel.Id, "theuserid", notifications) + assert.Equal(t, testChannelMember, member) + assert.Nil(t, err) + + api.On("DeleteChannelMember", "thechannelid", "theuserid").Return(nil).Once() + err = remote.DeleteChannelMember("thechannelid", "theuserid") + assert.Nil(t, err) + api.On("CreateUser", mock.AnythingOfType("*model.User")).Return(func(u *model.User) (*model.User, *model.AppError) { u.Id = "theuserid" return u, nil |