MM-16809: Added EnsureChannel Helper (#11852)
This PR adds EnsureChannel helper analogous to EnsureBot helper which creates a new channel if not exists and update the meta data of the channel if exists. Also, it will throw error if the type of existing channel do not match the type of new channel.
Этот коммит содержится в:
коммит произвёл
Ben Schumacher
родитель
8afbe9c6a4
Коммит
5aa24aedc8
@@ -10,6 +10,7 @@ import (
|
||||
const (
|
||||
INTERNAL_KEY_PREFIX = "mmi_"
|
||||
BOT_USER_KEY = INTERNAL_KEY_PREFIX + "botid"
|
||||
CHANNEL_KEY = INTERNAL_KEY_PREFIX + "channelid"
|
||||
)
|
||||
|
||||
// Starts the serving of a Mattermost plugin over net/rpc. gRPC is not yet supported.
|
||||
|
||||
111
plugin/helpers_channels.go
Обычный файл
111
plugin/helpers_channels.go
Обычный файл
@@ -0,0 +1,111 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package plugin
|
||||
|
||||
import (
|
||||
"github.com/mattermost/mattermost-server/model"
|
||||
"github.com/mattermost/mattermost-server/utils"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func (p *HelpersImpl) EnsureChannel(channel *model.Channel) (retChannelId string, retErr error) {
|
||||
// Must provide a channel with a name and teadId
|
||||
if channel == nil || len(channel.Name) < 1 || len(channel.TeamId) < 1 {
|
||||
return "", errors.New("passed a bad channel, nil or no name or no team id")
|
||||
}
|
||||
|
||||
// If we fail for any reason, this could be a race between creation of channel and
|
||||
// retrieval from another EnsureChannel. Just try the basic retrieve existing again.
|
||||
defer func() {
|
||||
if retChannelId == "" || retErr != nil {
|
||||
var err error
|
||||
var channelIdBytes []byte
|
||||
|
||||
err = utils.ProgressiveRetry(func() error {
|
||||
channelIdBytes, err = p.API.KVGet(CHANNEL_KEY)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
if err == nil && channelIdBytes != nil {
|
||||
retChannelId = string(channelIdBytes)
|
||||
retErr = nil
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
// Fetch channel ID from key value store
|
||||
channelIdBytes, kvGetErr := p.API.KVGet(CHANNEL_KEY)
|
||||
if kvGetErr != nil {
|
||||
// Failed to retrive the value of channel
|
||||
return "", errors.Wrap(kvGetErr, "failed to get channel ID")
|
||||
}
|
||||
|
||||
var existingChannel *model.Channel
|
||||
var channelGetErr *model.AppError
|
||||
|
||||
// If channel ID exists, get existing channel by ID else get it by Name
|
||||
if channelIdBytes != nil {
|
||||
existingChannel, channelGetErr = p.API.GetChannel(string(channelIdBytes))
|
||||
if channelGetErr != nil {
|
||||
return "", errors.Wrap(channelGetErr, "failed to get channel by ID")
|
||||
}
|
||||
} else {
|
||||
existingChannel, channelGetErr = p.API.GetChannelByName(channel.TeamId, channel.Name, false)
|
||||
if channelGetErr != nil {
|
||||
return "", errors.Wrap(channelGetErr, "failed to get channel by name")
|
||||
}
|
||||
}
|
||||
|
||||
// If channel exists, update the metadata
|
||||
if existingChannel != nil {
|
||||
return updateChannel(p, existingChannel, channel)
|
||||
}
|
||||
|
||||
// Create a new channel
|
||||
createdChannel, createChannelErr := p.API.CreateChannel(channel)
|
||||
if createChannelErr != nil {
|
||||
return "", errors.Wrap(createChannelErr, "failed to create channel")
|
||||
}
|
||||
|
||||
// Set the new channel id in key value store
|
||||
if kvSetErr := p.API.KVSet(CHANNEL_KEY, []byte(createdChannel.Id)); kvSetErr != nil {
|
||||
p.API.LogWarn("Failed to set created channel id.", "channelid", createdChannel.Id, "err", kvSetErr)
|
||||
}
|
||||
|
||||
return createdChannel.Id, nil
|
||||
}
|
||||
|
||||
func updateChannel(p *HelpersImpl, existing *model.Channel, new *model.Channel) (string, error) {
|
||||
// Update metadata of the channel
|
||||
if updateErr := updateChannelMeta(existing, new); updateErr != nil {
|
||||
return "", errors.Wrap(updateErr, "Failed to update the metadata of existing channel")
|
||||
}
|
||||
|
||||
// Send the updates to API
|
||||
updatedChannel, channelUpdateErr := p.API.UpdateChannel(existing)
|
||||
if channelUpdateErr != nil {
|
||||
return "", errors.Wrap(channelUpdateErr, "Failed to update the existing channel")
|
||||
}
|
||||
|
||||
// Channel exists!
|
||||
return updatedChannel.Id, nil
|
||||
}
|
||||
|
||||
func updateChannelMeta(existing *model.Channel, new *model.Channel) error {
|
||||
// Check if channels are of different types
|
||||
if existing.Type != new.Type {
|
||||
return errors.New("Channel type cannot be updated")
|
||||
}
|
||||
|
||||
// Update metadata of channel
|
||||
existing.Name = new.Name
|
||||
existing.DisplayName = new.DisplayName
|
||||
existing.Purpose = new.Purpose
|
||||
existing.Header = new.Header
|
||||
|
||||
return nil
|
||||
}
|
||||
297
plugin/helpers_channels_test.go
Обычный файл
297
plugin/helpers_channels_test.go
Обычный файл
@@ -0,0 +1,297 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
package plugin_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/mattermost/mattermost-server/model"
|
||||
"github.com/mattermost/mattermost-server/plugin"
|
||||
"github.com/mattermost/mattermost-server/plugin/plugintest"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestEnsureChannel(t *testing.T) {
|
||||
setupAPI := func() *plugintest.API {
|
||||
return &plugintest.API{}
|
||||
}
|
||||
|
||||
testChannel := &model.Channel{
|
||||
Id: model.NewId(),
|
||||
TeamId: model.NewId(),
|
||||
Type: "public",
|
||||
Name: "test_channel",
|
||||
DisplayName: "Test Channel",
|
||||
Purpose: "Testing EnsureChannel",
|
||||
Header: "Testing EnsureChannel",
|
||||
}
|
||||
|
||||
t.Run("bad parameters", func(t *testing.T) {
|
||||
t.Run("no channel", func(t *testing.T) {
|
||||
p := &plugin.HelpersImpl{}
|
||||
channelId, err := p.EnsureChannel(nil)
|
||||
assert.Equal(t, "", channelId)
|
||||
assert.NotNil(t, err)
|
||||
})
|
||||
t.Run("empty name", func(t *testing.T) {
|
||||
p := &plugin.HelpersImpl{}
|
||||
channelId, err := p.EnsureChannel(&model.Channel{
|
||||
Name: "",
|
||||
})
|
||||
assert.Equal(t, "", channelId)
|
||||
assert.NotNil(t, err)
|
||||
})
|
||||
t.Run("name without teamId", func(t *testing.T) {
|
||||
p := &plugin.HelpersImpl{}
|
||||
channelId, err := p.EnsureChannel(&model.Channel{
|
||||
Name: "test_channel",
|
||||
})
|
||||
assert.Equal(t, "", channelId)
|
||||
assert.NotNil(t, err)
|
||||
})
|
||||
t.Run("teamId without name", func(t *testing.T) {
|
||||
p := &plugin.HelpersImpl{}
|
||||
channelId, err := p.EnsureChannel(&model.Channel{
|
||||
TeamId: model.NewId(),
|
||||
})
|
||||
assert.Equal(t, "", channelId)
|
||||
assert.NotNil(t, err)
|
||||
})
|
||||
t.Run("teamId with empty name", func(t *testing.T) {
|
||||
p := &plugin.HelpersImpl{}
|
||||
channelId, err := p.EnsureChannel(&model.Channel{
|
||||
TeamId: model.NewId(),
|
||||
})
|
||||
assert.Equal(t, "", channelId)
|
||||
assert.NotNil(t, err)
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("if channel already exists in Key Value store", func(t *testing.T) {
|
||||
t.Run("should return an error if unable to get channel id", func(t *testing.T) {
|
||||
api := setupAPI()
|
||||
api.On("KVGet", plugin.CHANNEL_KEY).Return(nil, &model.AppError{})
|
||||
defer api.AssertExpectations(t)
|
||||
|
||||
p := &plugin.HelpersImpl{API: api}
|
||||
|
||||
channelId, err := p.EnsureChannel(testChannel)
|
||||
|
||||
assert.Equal(t, "", channelId)
|
||||
assert.NotNil(t, err)
|
||||
})
|
||||
t.Run("should return an error if unable to get channel", func(t *testing.T) {
|
||||
expectedChannelId := model.NewId()
|
||||
|
||||
api := setupAPI()
|
||||
api.On("KVGet", plugin.CHANNEL_KEY).Return([]byte(expectedChannelId), nil)
|
||||
api.On("GetChannel", expectedChannelId).Return(nil, &model.AppError{})
|
||||
|
||||
p := &plugin.HelpersImpl{API: api}
|
||||
|
||||
channelId, err := p.EnsureChannel(testChannel)
|
||||
|
||||
assert.Equal(t, "", channelId)
|
||||
assert.NotNil(t, err)
|
||||
})
|
||||
t.Run("should return an error if unable to update channel", func(t *testing.T) {
|
||||
expectedChannelId := model.NewId()
|
||||
|
||||
api := setupAPI()
|
||||
api.On("KVGet", plugin.CHANNEL_KEY).Return([]byte(expectedChannelId), nil)
|
||||
api.On("GetChannel", expectedChannelId).Return(testChannel, nil)
|
||||
api.On("UpdateChannel", testChannel).Return(nil, &model.AppError{})
|
||||
defer api.AssertExpectations(t)
|
||||
|
||||
p := &plugin.HelpersImpl{API: api}
|
||||
|
||||
channelId, err := p.EnsureChannel(testChannel)
|
||||
|
||||
assert.Equal(t, "", channelId)
|
||||
assert.NotNil(t, err)
|
||||
})
|
||||
t.Run("should return the Id of existing channel if metadata is same", func(t *testing.T) {
|
||||
api := setupAPI()
|
||||
api.On("KVGet", plugin.CHANNEL_KEY).Return([]byte(testChannel.Id), nil)
|
||||
api.On("GetChannel", testChannel.Id).Return(testChannel, nil)
|
||||
api.On("UpdateChannel", testChannel).Return(testChannel, nil)
|
||||
defer api.AssertExpectations(t)
|
||||
|
||||
p := &plugin.HelpersImpl{API: api}
|
||||
|
||||
channelId, err := p.EnsureChannel(testChannel)
|
||||
|
||||
assert.Equal(t, testChannel.Id, channelId)
|
||||
assert.Nil(t, err)
|
||||
})
|
||||
t.Run("should return error if channel type is different from existing one", func(t *testing.T) {
|
||||
privChannel := &model.Channel{
|
||||
Id: model.NewId(),
|
||||
Type: "private",
|
||||
TeamId: testChannel.TeamId,
|
||||
Name: testChannel.Name,
|
||||
}
|
||||
api := setupAPI()
|
||||
api.On("KVGet", plugin.CHANNEL_KEY).Return([]byte(testChannel.Id), nil)
|
||||
api.On("GetChannel", testChannel.Id).Return(privChannel, nil)
|
||||
defer api.AssertExpectations(t)
|
||||
|
||||
p := &plugin.HelpersImpl{API: api}
|
||||
|
||||
channelId, err := p.EnsureChannel(testChannel)
|
||||
|
||||
assert.Equal(t, "", channelId)
|
||||
assert.NotNil(t, err)
|
||||
})
|
||||
t.Run("should return the Id of updated channel if metadata is different", func(t *testing.T) {
|
||||
updatedChannel := &model.Channel{
|
||||
Id: model.NewId(),
|
||||
TeamId: testChannel.TeamId,
|
||||
Name: testChannel.Name,
|
||||
}
|
||||
api := setupAPI()
|
||||
api.On("KVGet", plugin.CHANNEL_KEY).Return([]byte(testChannel.Id), nil)
|
||||
api.On("GetChannel", testChannel.Id).Return(testChannel, nil)
|
||||
api.On("UpdateChannel", testChannel).Return(updatedChannel, nil)
|
||||
defer api.AssertExpectations(t)
|
||||
|
||||
p := &plugin.HelpersImpl{API: api}
|
||||
|
||||
channelId, err := p.EnsureChannel(testChannel)
|
||||
|
||||
assert.Equal(t, updatedChannel.Id, channelId)
|
||||
assert.Nil(t, err)
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("if channel is not in Key Value store but already exists", func(t *testing.T) {
|
||||
t.Run("should return an error if unable to get channel", func(t *testing.T) {
|
||||
api := setupAPI()
|
||||
api.On("KVGet", plugin.CHANNEL_KEY).Return(nil, nil)
|
||||
api.On("GetChannelByName", testChannel.TeamId, testChannel.Name, false).Return(nil, &model.AppError{})
|
||||
defer api.AssertExpectations(t)
|
||||
|
||||
p := &plugin.HelpersImpl{API: api}
|
||||
|
||||
channelId, err := p.EnsureChannel(testChannel)
|
||||
|
||||
assert.Equal(t, "", channelId)
|
||||
assert.NotNil(t, err)
|
||||
})
|
||||
t.Run("should return the Id of existing channel if metadata is same", func(t *testing.T) {
|
||||
api := setupAPI()
|
||||
api.On("KVGet", plugin.CHANNEL_KEY).Return(nil, nil)
|
||||
api.On("GetChannelByName", testChannel.TeamId, testChannel.Name, false).Return(testChannel, nil)
|
||||
api.On("UpdateChannel", testChannel).Return(testChannel, nil)
|
||||
defer api.AssertExpectations(t)
|
||||
|
||||
p := &plugin.HelpersImpl{API: api}
|
||||
|
||||
channelId, err := p.EnsureChannel(testChannel)
|
||||
|
||||
assert.Equal(t, testChannel.Id, channelId)
|
||||
assert.Nil(t, err)
|
||||
})
|
||||
t.Run("should return error if failed to update the channel", func(t *testing.T) {
|
||||
api := setupAPI()
|
||||
api.On("KVGet", plugin.CHANNEL_KEY).Return(nil, nil)
|
||||
api.On("GetChannelByName", testChannel.TeamId, testChannel.Name, false).Return(testChannel, nil)
|
||||
api.On("UpdateChannel", testChannel).Return(nil, &model.AppError{})
|
||||
defer api.AssertExpectations(t)
|
||||
|
||||
p := &plugin.HelpersImpl{API: api}
|
||||
|
||||
channelId, err := p.EnsureChannel(testChannel)
|
||||
|
||||
assert.Equal(t, "", channelId)
|
||||
assert.NotNil(t, err)
|
||||
})
|
||||
t.Run("should return the Id of updated channel if metadata is different", func(t *testing.T) {
|
||||
updatedChannel := &model.Channel{
|
||||
Id: model.NewId(),
|
||||
TeamId: testChannel.TeamId,
|
||||
Name: testChannel.Name,
|
||||
}
|
||||
api := setupAPI()
|
||||
api.On("KVGet", plugin.CHANNEL_KEY).Return(nil, nil)
|
||||
api.On("GetChannelByName", testChannel.TeamId, testChannel.Name, false).Return(testChannel, nil)
|
||||
api.On("UpdateChannel", testChannel).Return(updatedChannel, nil)
|
||||
defer api.AssertExpectations(t)
|
||||
|
||||
p := &plugin.HelpersImpl{API: api}
|
||||
|
||||
channelId, err := p.EnsureChannel(testChannel)
|
||||
|
||||
assert.Equal(t, updatedChannel.Id, channelId)
|
||||
assert.Nil(t, err)
|
||||
})
|
||||
t.Run("should return error if channel type is different from existing one", func(t *testing.T) {
|
||||
privChannel := &model.Channel{
|
||||
Id: model.NewId(),
|
||||
Type: "private",
|
||||
TeamId: testChannel.TeamId,
|
||||
Name: testChannel.Name,
|
||||
}
|
||||
api := setupAPI()
|
||||
api.On("KVGet", plugin.CHANNEL_KEY).Return(nil, nil)
|
||||
api.On("GetChannelByName", testChannel.TeamId, testChannel.Name, false).Return(privChannel, nil)
|
||||
defer api.AssertExpectations(t)
|
||||
|
||||
p := &plugin.HelpersImpl{API: api}
|
||||
|
||||
channelId, err := p.EnsureChannel(testChannel)
|
||||
|
||||
assert.Equal(t, "", channelId)
|
||||
assert.NotNil(t, err)
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("if channel does not exist", func(t *testing.T) {
|
||||
t.Run("should create new channel and return the Id", func(t *testing.T) {
|
||||
api := setupAPI()
|
||||
api.On("KVGet", plugin.CHANNEL_KEY).Return(nil, nil)
|
||||
api.On("GetChannelByName", testChannel.TeamId, testChannel.Name, false).Return(nil, nil)
|
||||
api.On("CreateChannel", testChannel).Return(testChannel, nil)
|
||||
api.On("KVSet", plugin.CHANNEL_KEY, []byte(testChannel.Id)).Return(nil)
|
||||
defer api.AssertExpectations(t)
|
||||
|
||||
p := &plugin.HelpersImpl{API: api}
|
||||
|
||||
channelId, err := p.EnsureChannel(testChannel)
|
||||
|
||||
assert.Equal(t, testChannel.Id, channelId)
|
||||
assert.Nil(t, err)
|
||||
})
|
||||
t.Run("should return error if unable to create new channel", func(t *testing.T) {
|
||||
api := setupAPI()
|
||||
api.On("KVGet", plugin.CHANNEL_KEY).Return(nil, nil)
|
||||
api.On("GetChannelByName", testChannel.TeamId, testChannel.Name, false).Return(nil, nil)
|
||||
api.On("CreateChannel", testChannel).Return(nil, &model.AppError{})
|
||||
defer api.AssertExpectations(t)
|
||||
|
||||
p := &plugin.HelpersImpl{API: api}
|
||||
|
||||
channelId, err := p.EnsureChannel(testChannel)
|
||||
|
||||
assert.Equal(t, "", channelId)
|
||||
assert.NotNil(t, err)
|
||||
})
|
||||
t.Run("should log and return id if unable to write to Key Value store", func(t *testing.T) {
|
||||
api := setupAPI()
|
||||
api.On("KVGet", plugin.CHANNEL_KEY).Return(nil, nil)
|
||||
api.On("GetChannelByName", testChannel.TeamId, testChannel.Name, false).Return(nil, nil)
|
||||
api.On("CreateChannel", testChannel).Return(testChannel, nil)
|
||||
api.On("KVSet", plugin.CHANNEL_KEY, []byte(testChannel.Id)).Return(&model.AppError{})
|
||||
api.On("LogWarn", "Failed to set created channel id.", "channelid", testChannel.Id, "err", &model.AppError{})
|
||||
defer api.AssertExpectations(t)
|
||||
|
||||
p := &plugin.HelpersImpl{API: api}
|
||||
|
||||
channelId, err := p.EnsureChannel(testChannel)
|
||||
|
||||
assert.Equal(t, testChannel.Id, channelId)
|
||||
assert.Nil(t, err)
|
||||
})
|
||||
})
|
||||
}
|
||||
Ссылка в новой задаче
Block a user