MM-25040: Restrict associated groups to channels when team is group-constrained. (#14619)
* MM-25040: Only return team-associated groups if the team is group-constrained. MM-25040: Prevents associating a group to a channel if the team doesn't have the group first. * MM-25040: Fix lints. * MM-25040: Still add the groupteam if the team is not group-constrained. * MM-25040: Wraps groupteam upsert in else branch for efficiency. * MM-25040: Removes unnecessary page iteration. * MM-25040: Fix typo. * MM-25040: Moves filtering to SQL. * MM-25040: Updates tests, check pagination. * MM-25040: Fix lint error. * MM-25040: Adds some more group store tests. * MM-25040: Fix for wrong test parameter.
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
c9cdeba1a7
Коммит
c529d5190a
@@ -158,6 +158,8 @@ type AppIface interface {
|
||||
GetEmojiStaticUrl(emojiName string) (string, *model.AppError)
|
||||
// GetEnvironmentConfig returns a map of configuration keys whose values have been overridden by an environment variable.
|
||||
GetEnvironmentConfig() map[string]interface{}
|
||||
// GetGroupsByTeam returns the paged list and the total count of group associated to the given team.
|
||||
GetGroupsByTeam(teamId string, opts model.GroupSearchOpts) ([]*model.GroupWithSchemeAdmin, int, *model.AppError)
|
||||
// GetHubForUserId returns the hub for a given user id.
|
||||
GetHubForUserId(userId string) *Hub
|
||||
// GetKnownUsers returns the list of user ids of users with any direct
|
||||
@@ -555,7 +557,6 @@ type AppIface interface {
|
||||
GetGroupsByChannel(channelId string, opts model.GroupSearchOpts) ([]*model.GroupWithSchemeAdmin, int, *model.AppError)
|
||||
GetGroupsByIDs(groupIDs []string) ([]*model.Group, *model.AppError)
|
||||
GetGroupsBySource(groupSource model.GroupSource) ([]*model.Group, *model.AppError)
|
||||
GetGroupsByTeam(teamId string, opts model.GroupSearchOpts) ([]*model.GroupWithSchemeAdmin, int, *model.AppError)
|
||||
GetGroupsByUserId(userId string) ([]*model.Group, *model.AppError)
|
||||
GetIncomingWebhook(hookId string) (*model.IncomingWebhook, *model.AppError)
|
||||
GetIncomingWebhooksForTeamPage(teamId string, page, perPage int) ([]*model.IncomingWebhook, *model.AppError)
|
||||
|
||||
57
app/group.go
57
app/group.go
@@ -4,6 +4,8 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/mattermost/mattermost-server/v5/model"
|
||||
)
|
||||
|
||||
@@ -86,6 +88,43 @@ func (a *App) UpsertGroupSyncable(groupSyncable *model.GroupSyncable) (*model.Gr
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// reject the syncable creation if the group isn't already associated to the parent team
|
||||
if groupSyncable.Type == model.GroupSyncableTypeChannel {
|
||||
var channel *model.Channel
|
||||
channel, err = a.Srv().Store.Channel().Get(groupSyncable.SyncableId, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var team *model.Team
|
||||
team, err = a.Srv().Store.Team().Get(channel.TeamId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if team.IsGroupConstrained() {
|
||||
var teamGroups []*model.GroupWithSchemeAdmin
|
||||
teamGroups, err = a.Srv().Store.Group().GetGroupsByTeam(channel.TeamId, model.GroupSearchOpts{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var permittedGroup bool
|
||||
for _, teamGroup := range teamGroups {
|
||||
if teamGroup.Group.Id == groupSyncable.GroupId {
|
||||
permittedGroup = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !permittedGroup {
|
||||
return nil, model.NewAppError("App.UpsertGroupSyncable", "group_not_associated_to_synced_team", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
} else {
|
||||
_, err = a.UpsertGroupSyncable(model.NewGroupTeam(groupSyncable.GroupId, team.Id, groupSyncable.AutoAdd))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if gs == nil {
|
||||
gs, err = a.Srv().Store.Group().CreateGroupSyncable(groupSyncable)
|
||||
if err != nil {
|
||||
@@ -98,23 +137,6 @@ func (a *App) UpsertGroupSyncable(groupSyncable *model.GroupSyncable) (*model.Gr
|
||||
}
|
||||
}
|
||||
|
||||
// if the type is channel, then upsert the associated GroupTeam [MM-14675]
|
||||
if gs.Type == model.GroupSyncableTypeChannel {
|
||||
channel, err := a.Srv().Store.Channel().Get(gs.SyncableId, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_, err = a.UpsertGroupSyncable(&model.GroupSyncable{
|
||||
GroupId: gs.GroupId,
|
||||
SyncableId: channel.TeamId,
|
||||
Type: model.GroupSyncableTypeTeam,
|
||||
AutoAdd: gs.AutoAdd,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
var messageWs *model.WebSocketEvent
|
||||
if gs.Type == model.GroupSyncableTypeTeam {
|
||||
messageWs = model.NewWebSocketEvent(model.WEBSOCKET_EVENT_RECEIVED_GROUP_ASSOCIATED_TO_TEAM, gs.SyncableId, "", "", nil)
|
||||
@@ -217,6 +239,7 @@ func (a *App) GetGroupsByChannel(channelId string, opts model.GroupSearchOpts) (
|
||||
return groups, int(count), nil
|
||||
}
|
||||
|
||||
// GetGroupsByTeam returns the paged list and the total count of group associated to the given team.
|
||||
func (a *App) GetGroupsByTeam(teamId string, opts model.GroupSearchOpts) ([]*model.GroupWithSchemeAdmin, int, *model.AppError) {
|
||||
groups, err := a.Srv().Store.Group().GetGroupsByTeam(teamId, opts)
|
||||
if err != nil {
|
||||
|
||||
@@ -158,6 +158,33 @@ func TestUpsertGroupSyncable(t *testing.T) {
|
||||
require.Equal(t, int64(0), gs.DeleteAt)
|
||||
}
|
||||
|
||||
func TestUpsertGroupSyncableTeamGroupConstrained(t *testing.T) {
|
||||
th := Setup(t).InitBasic()
|
||||
defer th.TearDown()
|
||||
|
||||
group1 := th.CreateGroup()
|
||||
group2 := th.CreateGroup()
|
||||
|
||||
team := th.CreateTeam()
|
||||
team.GroupConstrained = model.NewBool(true)
|
||||
team, err := th.App.UpdateTeam(team)
|
||||
require.Nil(t, err)
|
||||
_, err = th.App.UpsertGroupSyncable(model.NewGroupTeam(group1.Id, team.Id, false))
|
||||
|
||||
channel := th.CreateChannel(team)
|
||||
|
||||
_, err = th.App.UpsertGroupSyncable(model.NewGroupChannel(group2.Id, channel.Id, false))
|
||||
require.NotNil(t, err)
|
||||
require.Equal(t, err.Id, "group_not_associated_to_synced_team")
|
||||
|
||||
gs, err := th.App.GetGroupSyncable(group2.Id, channel.Id, model.GroupSyncableTypeChannel)
|
||||
require.Nil(t, gs)
|
||||
require.NotNil(t, err)
|
||||
|
||||
_, err = th.App.UpsertGroupSyncable(model.NewGroupChannel(group1.Id, channel.Id, false))
|
||||
require.Nil(t, err)
|
||||
}
|
||||
|
||||
func TestGetGroupSyncable(t *testing.T) {
|
||||
th := Setup(t).InitBasic()
|
||||
defer th.TearDown()
|
||||
|
||||
Ссылка в новой задаче
Block a user