github.com/mattermosttest/mattermost-server/v5@v5.0.0-20200917143240-9dfa12e121f9/app/group.go (about)

     1  // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
     2  // See LICENSE.txt for license information.
     3  
     4  package app
     5  
     6  import (
     7  	"errors"
     8  	"net/http"
     9  
    10  	"github.com/mattermost/mattermost-server/v5/model"
    11  	"github.com/mattermost/mattermost-server/v5/store"
    12  )
    13  
    14  func (a *App) GetGroup(id string) (*model.Group, *model.AppError) {
    15  	return a.Srv().Store.Group().Get(id)
    16  }
    17  
    18  func (a *App) GetGroupByName(name string, opts model.GroupSearchOpts) (*model.Group, *model.AppError) {
    19  	return a.Srv().Store.Group().GetByName(name, opts)
    20  }
    21  
    22  func (a *App) GetGroupByRemoteID(remoteID string, groupSource model.GroupSource) (*model.Group, *model.AppError) {
    23  	return a.Srv().Store.Group().GetByRemoteID(remoteID, groupSource)
    24  }
    25  
    26  func (a *App) GetGroupsBySource(groupSource model.GroupSource) ([]*model.Group, *model.AppError) {
    27  	return a.Srv().Store.Group().GetAllBySource(groupSource)
    28  }
    29  
    30  func (a *App) GetGroupsByUserId(userId string) ([]*model.Group, *model.AppError) {
    31  	return a.Srv().Store.Group().GetByUser(userId)
    32  }
    33  
    34  func (a *App) CreateGroup(group *model.Group) (*model.Group, *model.AppError) {
    35  	return a.Srv().Store.Group().Create(group)
    36  }
    37  
    38  func (a *App) UpdateGroup(group *model.Group) (*model.Group, *model.AppError) {
    39  	updatedGroup, err := a.Srv().Store.Group().Update(group)
    40  
    41  	if err == nil {
    42  		messageWs := model.NewWebSocketEvent(model.WEBSOCKET_EVENT_RECEIVED_GROUP, "", "", "", nil)
    43  		messageWs.Add("group", updatedGroup.ToJson())
    44  		a.Publish(messageWs)
    45  	}
    46  
    47  	return updatedGroup, err
    48  }
    49  
    50  func (a *App) DeleteGroup(groupID string) (*model.Group, *model.AppError) {
    51  	deletedGroup, err := a.Srv().Store.Group().Delete(groupID)
    52  
    53  	if err == nil {
    54  		messageWs := model.NewWebSocketEvent(model.WEBSOCKET_EVENT_RECEIVED_GROUP, "", "", "", nil)
    55  		messageWs.Add("group", deletedGroup.ToJson())
    56  		a.Publish(messageWs)
    57  	}
    58  
    59  	return deletedGroup, err
    60  }
    61  
    62  func (a *App) GetGroupMemberCount(groupID string) (int64, *model.AppError) {
    63  	return a.Srv().Store.Group().GetMemberCount(groupID)
    64  }
    65  
    66  func (a *App) GetGroupMemberUsers(groupID string) ([]*model.User, *model.AppError) {
    67  	return a.Srv().Store.Group().GetMemberUsers(groupID)
    68  }
    69  
    70  func (a *App) GetGroupMemberUsersPage(groupID string, page int, perPage int) ([]*model.User, int, *model.AppError) {
    71  	members, err := a.Srv().Store.Group().GetMemberUsersPage(groupID, page, perPage)
    72  	if err != nil {
    73  		return nil, 0, err
    74  	}
    75  
    76  	count, err := a.GetGroupMemberCount(groupID)
    77  	if err != nil {
    78  		return nil, 0, err
    79  	}
    80  	return members, int(count), nil
    81  }
    82  
    83  func (a *App) UpsertGroupMember(groupID string, userID string) (*model.GroupMember, *model.AppError) {
    84  	return a.Srv().Store.Group().UpsertMember(groupID, userID)
    85  }
    86  
    87  func (a *App) DeleteGroupMember(groupID string, userID string) (*model.GroupMember, *model.AppError) {
    88  	return a.Srv().Store.Group().DeleteMember(groupID, userID)
    89  }
    90  
    91  func (a *App) UpsertGroupSyncable(groupSyncable *model.GroupSyncable) (*model.GroupSyncable, *model.AppError) {
    92  	gs, err := a.Srv().Store.Group().GetGroupSyncable(groupSyncable.GroupId, groupSyncable.SyncableId, groupSyncable.Type)
    93  	if err != nil && err.Id != "store.sql_group.no_rows" {
    94  		return nil, err
    95  	}
    96  
    97  	// reject the syncable creation if the group isn't already associated to the parent team
    98  	if groupSyncable.Type == model.GroupSyncableTypeChannel {
    99  		channel, nErr := a.Srv().Store.Channel().Get(groupSyncable.SyncableId, true)
   100  		if nErr != nil {
   101  			var nfErr *store.ErrNotFound
   102  			switch {
   103  			case errors.As(nErr, &nfErr):
   104  				return nil, model.NewAppError("UpsertGroupSyncable", "app.channel.get.existing.app_error", nil, nfErr.Error(), http.StatusNotFound)
   105  			default:
   106  				return nil, model.NewAppError("UpsertGroupSyncable", "app.channel.get.find.app_error", nil, nErr.Error(), http.StatusInternalServerError)
   107  			}
   108  		}
   109  
   110  		var team *model.Team
   111  		team, err = a.Srv().Store.Team().Get(channel.TeamId)
   112  		if err != nil {
   113  			return nil, err
   114  		}
   115  		if team.IsGroupConstrained() {
   116  			var teamGroups []*model.GroupWithSchemeAdmin
   117  			teamGroups, err = a.Srv().Store.Group().GetGroupsByTeam(channel.TeamId, model.GroupSearchOpts{})
   118  			if err != nil {
   119  				return nil, err
   120  			}
   121  			var permittedGroup bool
   122  			for _, teamGroup := range teamGroups {
   123  				if teamGroup.Group.Id == groupSyncable.GroupId {
   124  					permittedGroup = true
   125  					break
   126  				}
   127  			}
   128  			if !permittedGroup {
   129  				return nil, model.NewAppError("App.UpsertGroupSyncable", "group_not_associated_to_synced_team", nil, "", http.StatusBadRequest)
   130  			}
   131  		} else {
   132  			_, err = a.UpsertGroupSyncable(model.NewGroupTeam(groupSyncable.GroupId, team.Id, groupSyncable.AutoAdd))
   133  			if err != nil {
   134  				return nil, err
   135  			}
   136  		}
   137  	}
   138  
   139  	if gs == nil {
   140  		gs, err = a.Srv().Store.Group().CreateGroupSyncable(groupSyncable)
   141  		if err != nil {
   142  			return nil, err
   143  		}
   144  	} else {
   145  		gs, err = a.Srv().Store.Group().UpdateGroupSyncable(groupSyncable)
   146  		if err != nil {
   147  			return nil, err
   148  		}
   149  	}
   150  
   151  	var messageWs *model.WebSocketEvent
   152  	if gs.Type == model.GroupSyncableTypeTeam {
   153  		messageWs = model.NewWebSocketEvent(model.WEBSOCKET_EVENT_RECEIVED_GROUP_ASSOCIATED_TO_TEAM, gs.SyncableId, "", "", nil)
   154  	} else {
   155  		messageWs = model.NewWebSocketEvent(model.WEBSOCKET_EVENT_RECEIVED_GROUP_ASSOCIATED_TO_CHANNEL, "", gs.SyncableId, "", nil)
   156  	}
   157  	messageWs.Add("group_id", gs.GroupId)
   158  	a.Publish(messageWs)
   159  
   160  	return gs, nil
   161  }
   162  
   163  func (a *App) GetGroupSyncable(groupID string, syncableID string, syncableType model.GroupSyncableType) (*model.GroupSyncable, *model.AppError) {
   164  	return a.Srv().Store.Group().GetGroupSyncable(groupID, syncableID, syncableType)
   165  }
   166  
   167  func (a *App) GetGroupSyncables(groupID string, syncableType model.GroupSyncableType) ([]*model.GroupSyncable, *model.AppError) {
   168  	return a.Srv().Store.Group().GetAllGroupSyncablesByGroupId(groupID, syncableType)
   169  }
   170  
   171  func (a *App) UpdateGroupSyncable(groupSyncable *model.GroupSyncable) (*model.GroupSyncable, *model.AppError) {
   172  	var gs *model.GroupSyncable
   173  	var err *model.AppError
   174  
   175  	if groupSyncable.DeleteAt == 0 {
   176  		// updating a *deleted* GroupSyncable, so no need to ensure the GroupTeam is present (as done in the upsert)
   177  		gs, err = a.Srv().Store.Group().UpdateGroupSyncable(groupSyncable)
   178  	} else {
   179  		// do an upsert to ensure that there's an associated GroupTeam
   180  		gs, err = a.UpsertGroupSyncable(groupSyncable)
   181  	}
   182  	if err != nil {
   183  		return nil, err
   184  	}
   185  
   186  	return gs, nil
   187  }
   188  
   189  func (a *App) DeleteGroupSyncable(groupID string, syncableID string, syncableType model.GroupSyncableType) (*model.GroupSyncable, *model.AppError) {
   190  	gs, err := a.Srv().Store.Group().DeleteGroupSyncable(groupID, syncableID, syncableType)
   191  	if err != nil {
   192  		return nil, err
   193  	}
   194  
   195  	// if a GroupTeam is being deleted delete all associated GroupChannels
   196  	if gs.Type == model.GroupSyncableTypeTeam {
   197  		allGroupChannels, err := a.Srv().Store.Group().GetAllGroupSyncablesByGroupId(gs.GroupId, model.GroupSyncableTypeChannel)
   198  		if err != nil {
   199  			return nil, err
   200  		}
   201  
   202  		for _, groupChannel := range allGroupChannels {
   203  			_, err = a.Srv().Store.Group().DeleteGroupSyncable(groupChannel.GroupId, groupChannel.SyncableId, groupChannel.Type)
   204  			if err != nil {
   205  				return nil, err
   206  			}
   207  		}
   208  	}
   209  
   210  	var messageWs *model.WebSocketEvent
   211  	if gs.Type == model.GroupSyncableTypeTeam {
   212  		messageWs = model.NewWebSocketEvent(model.WEBSOCKET_EVENT_RECEIVED_GROUP_NOT_ASSOCIATED_TO_TEAM, gs.SyncableId, "", "", nil)
   213  	} else {
   214  		messageWs = model.NewWebSocketEvent(model.WEBSOCKET_EVENT_RECEIVED_GROUP_NOT_ASSOCIATED_TO_CHANNEL, "", gs.SyncableId, "", nil)
   215  	}
   216  
   217  	messageWs.Add("group_id", gs.GroupId)
   218  	a.Publish(messageWs)
   219  
   220  	return gs, nil
   221  }
   222  
   223  func (a *App) TeamMembersToAdd(since int64, teamID *string) ([]*model.UserTeamIDPair, *model.AppError) {
   224  	return a.Srv().Store.Group().TeamMembersToAdd(since, teamID)
   225  }
   226  
   227  func (a *App) ChannelMembersToAdd(since int64, channelID *string) ([]*model.UserChannelIDPair, *model.AppError) {
   228  	return a.Srv().Store.Group().ChannelMembersToAdd(since, channelID)
   229  }
   230  
   231  func (a *App) TeamMembersToRemove(teamID *string) ([]*model.TeamMember, *model.AppError) {
   232  	return a.Srv().Store.Group().TeamMembersToRemove(teamID)
   233  }
   234  
   235  func (a *App) ChannelMembersToRemove(teamID *string) ([]*model.ChannelMember, *model.AppError) {
   236  	return a.Srv().Store.Group().ChannelMembersToRemove(teamID)
   237  }
   238  
   239  func (a *App) GetGroupsByChannel(channelId string, opts model.GroupSearchOpts) ([]*model.GroupWithSchemeAdmin, int, *model.AppError) {
   240  	groups, err := a.Srv().Store.Group().GetGroupsByChannel(channelId, opts)
   241  	if err != nil {
   242  		return nil, 0, err
   243  	}
   244  
   245  	count, err := a.Srv().Store.Group().CountGroupsByChannel(channelId, opts)
   246  	if err != nil {
   247  		return nil, 0, err
   248  	}
   249  
   250  	return groups, int(count), nil
   251  }
   252  
   253  // GetGroupsByTeam returns the paged list and the total count of group associated to the given team.
   254  func (a *App) GetGroupsByTeam(teamId string, opts model.GroupSearchOpts) ([]*model.GroupWithSchemeAdmin, int, *model.AppError) {
   255  	groups, err := a.Srv().Store.Group().GetGroupsByTeam(teamId, opts)
   256  	if err != nil {
   257  		return nil, 0, err
   258  	}
   259  
   260  	count, err := a.Srv().Store.Group().CountGroupsByTeam(teamId, opts)
   261  	if err != nil {
   262  		return nil, 0, err
   263  	}
   264  
   265  	return groups, int(count), nil
   266  }
   267  
   268  func (a *App) GetGroupsAssociatedToChannelsByTeam(teamId string, opts model.GroupSearchOpts) (map[string][]*model.GroupWithSchemeAdmin, *model.AppError) {
   269  	groupsAssociatedByChannelId, err := a.Srv().Store.Group().GetGroupsAssociatedToChannelsByTeam(teamId, opts)
   270  	if err != nil {
   271  		return nil, err
   272  	}
   273  
   274  	return groupsAssociatedByChannelId, nil
   275  }
   276  
   277  func (a *App) GetGroups(page, perPage int, opts model.GroupSearchOpts) ([]*model.Group, *model.AppError) {
   278  	return a.Srv().Store.Group().GetGroups(page, perPage, opts)
   279  }
   280  
   281  // TeamMembersMinusGroupMembers returns the set of users on the given team minus the set of users in the given
   282  // groups.
   283  //
   284  // The result can be used, for example, to determine the set of users who would be removed from a team if the team
   285  // were group-constrained with the given groups.
   286  func (a *App) TeamMembersMinusGroupMembers(teamID string, groupIDs []string, page, perPage int) ([]*model.UserWithGroups, int64, *model.AppError) {
   287  	users, err := a.Srv().Store.Group().TeamMembersMinusGroupMembers(teamID, groupIDs, page, perPage)
   288  	if err != nil {
   289  		return nil, 0, err
   290  	}
   291  
   292  	// parse all group ids of all users
   293  	allUsersGroupIDMap := map[string]bool{}
   294  	for _, user := range users {
   295  		for _, groupID := range user.GetGroupIDs() {
   296  			allUsersGroupIDMap[groupID] = true
   297  		}
   298  	}
   299  
   300  	// create a slice of distinct group ids
   301  	var allUsersGroupIDSlice []string
   302  	for key := range allUsersGroupIDMap {
   303  		allUsersGroupIDSlice = append(allUsersGroupIDSlice, key)
   304  	}
   305  
   306  	// retrieve groups from DB
   307  	groups, err := a.GetGroupsByIDs(allUsersGroupIDSlice)
   308  	if err != nil {
   309  		return nil, 0, err
   310  	}
   311  
   312  	// map groups by id
   313  	groupMap := map[string]*model.Group{}
   314  	for _, group := range groups {
   315  		groupMap[group.Id] = group
   316  	}
   317  
   318  	// populate each instance's groups field
   319  	for _, user := range users {
   320  		user.Groups = []*model.Group{}
   321  		for _, groupID := range user.GetGroupIDs() {
   322  			group, ok := groupMap[groupID]
   323  			if ok {
   324  				user.Groups = append(user.Groups, group)
   325  			}
   326  		}
   327  	}
   328  
   329  	totalCount, err := a.Srv().Store.Group().CountTeamMembersMinusGroupMembers(teamID, groupIDs)
   330  	if err != nil {
   331  		return nil, 0, err
   332  	}
   333  	return users, totalCount, nil
   334  }
   335  
   336  func (a *App) GetGroupsByIDs(groupIDs []string) ([]*model.Group, *model.AppError) {
   337  	return a.Srv().Store.Group().GetByIDs(groupIDs)
   338  }
   339  
   340  // ChannelMembersMinusGroupMembers returns the set of users in the given channel minus the set of users in the given
   341  // groups.
   342  //
   343  // The result can be used, for example, to determine the set of users who would be removed from a channel if the
   344  // channel were group-constrained with the given groups.
   345  func (a *App) ChannelMembersMinusGroupMembers(channelID string, groupIDs []string, page, perPage int) ([]*model.UserWithGroups, int64, *model.AppError) {
   346  	users, err := a.Srv().Store.Group().ChannelMembersMinusGroupMembers(channelID, groupIDs, page, perPage)
   347  	if err != nil {
   348  		return nil, 0, err
   349  	}
   350  
   351  	// parse all group ids of all users
   352  	allUsersGroupIDMap := map[string]bool{}
   353  	for _, user := range users {
   354  		for _, groupID := range user.GetGroupIDs() {
   355  			allUsersGroupIDMap[groupID] = true
   356  		}
   357  	}
   358  
   359  	// create a slice of distinct group ids
   360  	var allUsersGroupIDSlice []string
   361  	for key := range allUsersGroupIDMap {
   362  		allUsersGroupIDSlice = append(allUsersGroupIDSlice, key)
   363  	}
   364  
   365  	// retrieve groups from DB
   366  	groups, err := a.GetGroupsByIDs(allUsersGroupIDSlice)
   367  	if err != nil {
   368  		return nil, 0, err
   369  	}
   370  
   371  	// map groups by id
   372  	groupMap := map[string]*model.Group{}
   373  	for _, group := range groups {
   374  		groupMap[group.Id] = group
   375  	}
   376  
   377  	// populate each instance's groups field
   378  	for _, user := range users {
   379  		user.Groups = []*model.Group{}
   380  		for _, groupID := range user.GetGroupIDs() {
   381  			group, ok := groupMap[groupID]
   382  			if ok {
   383  				user.Groups = append(user.Groups, group)
   384  			}
   385  		}
   386  	}
   387  
   388  	totalCount, err := a.Srv().Store.Group().CountChannelMembersMinusGroupMembers(channelID, groupIDs)
   389  	if err != nil {
   390  		return nil, 0, err
   391  	}
   392  	return users, totalCount, nil
   393  }
   394  
   395  // UserIsInAdminRoleGroup returns true at least one of the user's groups are configured to set the members as
   396  // admins in the given syncable.
   397  func (a *App) UserIsInAdminRoleGroup(userID, syncableID string, syncableType model.GroupSyncableType) (bool, *model.AppError) {
   398  	groupIDs, err := a.Srv().Store.Group().AdminRoleGroupsForSyncableMember(userID, syncableID, syncableType)
   399  	if err != nil {
   400  		return false, err
   401  	}
   402  
   403  	if len(groupIDs) == 0 {
   404  		return false, nil
   405  	}
   406  
   407  	return true, nil
   408  }