Adds Shared Channel related API endpoints (#27436)

* Adds Shared Channel management API endpoints

New endpoints for the following routes are added:

- Get Shared Channel Remotes by Remote Cluster at `GET
/api/v4/remotecluster/{remote_id}/sharedchannelremotes`
- Invite Remote Cluster to Channel at `POST
/api/v4/remotecluster/{remote_id}/channels/invite`
- Uninvite Remote Cluster to Channel at `POST
/api/v4/remotecluster/{remote_id}/channels/uninvite`

These endpoints are planned to be used from the system console, and
gated through the `manage_secure_connections` permission.

* Adds i18n messages for API errors

* Fix pagination flaky test

* Fix linter

* Adds the posibility of filtering shared channel remotes by home

---------

Co-authored-by: Mattermost Build <build@mattermost.com>
Этот коммит содержится в:
Miguel de la Cruz
2024-08-29 12:46:37 +02:00
коммит произвёл GitHub
родитель 60ffd00d30
Коммит 3dc0e63c03
20 изменённых файлов: 819 добавлений и 54 удалений

Просмотреть файл

@@ -278,9 +278,9 @@ func (_m *SharedChannelStore) GetRemoteForUser(remoteId string, userId string) (
return r0, r1
}
// GetRemotes provides a mock function with given fields: opts
func (_m *SharedChannelStore) GetRemotes(opts model.SharedChannelRemoteFilterOpts) ([]*model.SharedChannelRemote, error) {
ret := _m.Called(opts)
// GetRemotes provides a mock function with given fields: offset, limit, opts
func (_m *SharedChannelStore) GetRemotes(offset int, limit int, opts model.SharedChannelRemoteFilterOpts) ([]*model.SharedChannelRemote, error) {
ret := _m.Called(offset, limit, opts)
if len(ret) == 0 {
panic("no return value specified for GetRemotes")
@@ -288,19 +288,19 @@ func (_m *SharedChannelStore) GetRemotes(opts model.SharedChannelRemoteFilterOpt
var r0 []*model.SharedChannelRemote
var r1 error
if rf, ok := ret.Get(0).(func(model.SharedChannelRemoteFilterOpts) ([]*model.SharedChannelRemote, error)); ok {
return rf(opts)
if rf, ok := ret.Get(0).(func(int, int, model.SharedChannelRemoteFilterOpts) ([]*model.SharedChannelRemote, error)); ok {
return rf(offset, limit, opts)
}
if rf, ok := ret.Get(0).(func(model.SharedChannelRemoteFilterOpts) []*model.SharedChannelRemote); ok {
r0 = rf(opts)
if rf, ok := ret.Get(0).(func(int, int, model.SharedChannelRemoteFilterOpts) []*model.SharedChannelRemote); ok {
r0 = rf(offset, limit, opts)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).([]*model.SharedChannelRemote)
}
}
if rf, ok := ret.Get(1).(func(model.SharedChannelRemoteFilterOpts) error); ok {
r1 = rf(opts)
if rf, ok := ret.Get(1).(func(int, int, model.SharedChannelRemoteFilterOpts) error); ok {
r1 = rf(offset, limit, opts)
} else {
r1 = ret.Error(1)
}

Просмотреть файл

@@ -191,16 +191,17 @@ func testGetSharedChannels(t *testing.T, rctx request.CTX, ss store.Store) {
creator := model.NewId()
team1 := model.NewId()
team2 := model.NewId()
rid := model.NewId()
rid1 := model.NewId()
rid2 := model.NewId()
data := []model.SharedChannel{
{CreatorId: creator, TeamId: team1, ShareName: "test1", Home: true},
{CreatorId: creator, TeamId: team1, ShareName: "test2", Home: false, RemoteId: rid},
{CreatorId: creator, TeamId: team1, ShareName: "test3", Home: false, RemoteId: rid},
{CreatorId: creator, TeamId: team1, ShareName: "test2", Home: false, RemoteId: rid1},
{CreatorId: creator, TeamId: team1, ShareName: "test3", Home: false, RemoteId: rid2},
{CreatorId: creator, TeamId: team1, ShareName: "test4", Home: true},
{CreatorId: creator, TeamId: team2, ShareName: "test5", Home: true},
{CreatorId: creator, TeamId: team2, ShareName: "test6", Home: false, RemoteId: rid},
{CreatorId: creator, TeamId: team2, ShareName: "test7", Home: false, RemoteId: rid},
{CreatorId: creator, TeamId: team2, ShareName: "test6", Home: false, RemoteId: rid1},
{CreatorId: creator, TeamId: team2, ShareName: "test7", Home: false, RemoteId: rid2},
{CreatorId: creator, TeamId: team2, ShareName: "test8", Home: true},
{CreatorId: creator, TeamId: team2, ShareName: "test9", Home: true},
}
@@ -407,7 +408,7 @@ func testDeleteSharedChannel(t *testing.T, rctx request.CTX, ss store.Store) {
require.Nil(t, sc)
// make sure the remotes were deleted.
remotes, err := ss.SharedChannel().GetRemotes(model.SharedChannelRemoteFilterOpts{ChannelId: channel.Id})
remotes, err := ss.SharedChannel().GetRemotes(0, 999999, model.SharedChannelRemoteFilterOpts{ChannelId: channel.Id})
require.NoError(t, err)
require.Len(t, remotes, 0, "expected empty remotes list")
@@ -578,21 +579,29 @@ func testGetSharedChannelRemotes(t *testing.T, rctx request.CTX, ss store.Store)
creator := model.NewId()
remoteId := model.NewId()
remoteId2 := model.NewId()
data := []model.SharedChannelRemote{
{ChannelId: channel.Id, CreatorId: creator, RemoteId: model.NewId(), IsInviteConfirmed: true},
{ChannelId: channel.Id, CreatorId: creator, RemoteId: model.NewId(), IsInviteConfirmed: true},
{ChannelId: channel.Id, CreatorId: creator, RemoteId: model.NewId(), IsInviteConfirmed: true},
{ChannelId: channel.Id, CreatorId: creator, RemoteId: remoteId2, IsInviteConfirmed: true},
{CreatorId: creator, RemoteId: remoteId, IsInviteConfirmed: true},
{CreatorId: creator, RemoteId: remoteId, IsInviteConfirmed: true},
{CreatorId: creator, RemoteId: remoteId},
}
// first three remotes are homed locally
_, scErr := shareChannel(ss, channel, true, "")
require.NoError(t, scErr)
for i, r := range data {
if r.ChannelId == "" {
c, err := createTestChannel(ss, rctx, "test_remotes_get2_"+strconv.Itoa(i))
require.NoError(t, err)
r.ChannelId = c.Id
// next three remotes are homed outside
shareChannel(ss, c, false, r.RemoteId)
}
_, err := ss.SharedChannel().SaveRemote(&r)
require.NoError(t, err, "error saving shared channel remote")
@@ -602,7 +611,7 @@ func testGetSharedChannelRemotes(t *testing.T, rctx request.CTX, ss store.Store)
opts := model.SharedChannelRemoteFilterOpts{
ChannelId: channel.Id,
}
remotes, err := ss.SharedChannel().GetRemotes(opts)
remotes, err := ss.SharedChannel().GetRemotes(0, 999999, opts)
require.NoError(t, err, "should not error", err)
require.Len(t, remotes, 3)
for _, r := range remotes {
@@ -614,7 +623,7 @@ func testGetSharedChannelRemotes(t *testing.T, rctx request.CTX, ss store.Store)
opts := model.SharedChannelRemoteFilterOpts{
ChannelId: model.NewId(),
}
remotes, err := ss.SharedChannel().GetRemotes(opts)
remotes, err := ss.SharedChannel().GetRemotes(0, 999999, opts)
require.NoError(t, err, "should not error", err)
require.Len(t, remotes, 0)
})
@@ -623,7 +632,7 @@ func testGetSharedChannelRemotes(t *testing.T, rctx request.CTX, ss store.Store)
opts := model.SharedChannelRemoteFilterOpts{
RemoteId: remoteId,
}
remotes, err := ss.SharedChannel().GetRemotes(opts)
remotes, err := ss.SharedChannel().GetRemotes(0, 999999, opts)
require.NoError(t, err, "should not error", err)
require.Len(t, remotes, 2) // only confirmed invitations
for _, r := range remotes {
@@ -636,7 +645,7 @@ func testGetSharedChannelRemotes(t *testing.T, rctx request.CTX, ss store.Store)
opts := model.SharedChannelRemoteFilterOpts{
RemoteId: model.NewId(),
}
remotes, err := ss.SharedChannel().GetRemotes(opts)
remotes, err := ss.SharedChannel().GetRemotes(0, 999999, opts)
require.NoError(t, err, "should not error", err)
require.Len(t, remotes, 0)
})
@@ -646,13 +655,61 @@ func testGetSharedChannelRemotes(t *testing.T, rctx request.CTX, ss store.Store)
RemoteId: remoteId,
InclUnconfirmed: true,
}
remotes, err := ss.SharedChannel().GetRemotes(opts)
remotes, err := ss.SharedChannel().GetRemotes(0, 999999, opts)
require.NoError(t, err, "should not error", err)
require.Len(t, remotes, 3)
for _, r := range remotes {
require.Equal(t, remoteId, r.RemoteId)
}
})
t.Run("Get shared channel remotes with bad options", func(t *testing.T) {
opts := model.SharedChannelRemoteFilterOpts{
ExcludeHome: true,
ExcludeRemote: true,
}
remotes, err := ss.SharedChannel().GetRemotes(0, 999999, opts)
require.Error(t, err, "error expected")
require.Empty(t, remotes)
})
t.Run("Get shared channel remotes excluding shared from outside", func(t *testing.T) {
opts := model.SharedChannelRemoteFilterOpts{
ExcludeRemote: true,
}
remotes, err := ss.SharedChannel().GetRemotes(0, 999999, opts)
require.NoError(t, err, "should not error", err)
require.Len(t, remotes, 3)
})
t.Run("Get shared channel remotes excluding shared from home", func(t *testing.T) {
opts := model.SharedChannelRemoteFilterOpts{
ExcludeHome: true,
}
remotes, err := ss.SharedChannel().GetRemotes(0, 999999, opts)
require.NoError(t, err, "should not error", err)
require.Len(t, remotes, 2)
})
t.Run("Get shared channel remotes excluding shared from outside and by remote_id", func(t *testing.T) {
opts := model.SharedChannelRemoteFilterOpts{
ExcludeRemote: true,
RemoteId: remoteId2,
}
remotes, err := ss.SharedChannel().GetRemotes(0, 999999, opts)
require.NoError(t, err, "should not error", err)
require.Len(t, remotes, 1)
})
t.Run("Get shared channel remotes excluding shared from home including unconfirmed", func(t *testing.T) {
opts := model.SharedChannelRemoteFilterOpts{
ExcludeHome: true,
InclUnconfirmed: true,
}
remotes, err := ss.SharedChannel().GetRemotes(0, 999999, opts)
require.NoError(t, err, "should not error", err)
require.Len(t, remotes, 3)
})
}
func testHasRemote(t *testing.T, rctx request.CTX, ss store.Store) {
@@ -892,21 +949,26 @@ func createSharedTestChannel(ss store.Store, rctx request.CTX, name string, shar
}
if shared {
sc := &model.SharedChannel{
ChannelId: channel.Id,
TeamId: channel.TeamId,
CreatorId: channel.CreatorId,
ShareName: channel.Name,
Home: true,
}
_, err = ss.SharedChannel().Save(sc)
if err != nil {
if _, err := shareChannel(ss, channel, true, ""); err != nil {
return nil, err
}
}
return channel, nil
}
func shareChannel(ss store.Store, channel *model.Channel, home bool, remoteId string) (*model.SharedChannel, error) {
sc := &model.SharedChannel{
ChannelId: channel.Id,
TeamId: channel.TeamId,
CreatorId: channel.CreatorId,
ShareName: channel.Name,
Home: home,
RemoteId: remoteId,
}
return ss.SharedChannel().Save(sc)
}
func clearSharedChannels(ss store.Store) error {
opts := model.SharedChannelFilterOpts{}
all, err := ss.SharedChannel().GetAll(0, 1000, opts)