github.com/haalcala/mattermost-server-change-repo/v5@v5.33.2/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  	group, err := a.Srv().Store.Group().Get(id)
    16  	if err != nil {
    17  		var nfErr *store.ErrNotFound
    18  		switch {
    19  		case errors.As(err, &nfErr):
    20  			return nil, model.NewAppError("GetGroup", "app.group.no_rows", nil, nfErr.Error(), http.StatusNotFound)
    21  		default:
    22  			return nil, model.NewAppError("GetGroup", "app.select_error", nil, err.Error(), http.StatusInternalServerError)
    23  		}
    24  	}
    25  
    26  	return group, nil
    27  }
    28  
    29  func (a *App) GetGroupByName(name string, opts model.GroupSearchOpts) (*model.Group, *model.AppError) {
    30  	group, err := a.Srv().Store.Group().GetByName(name, opts)
    31  	if err != nil {
    32  		var nfErr *store.ErrNotFound
    33  		switch {
    34  		case errors.As(err, &nfErr):
    35  			return nil, model.NewAppError("GetGroupByName", "app.group.no_rows", nil, nfErr.Error(), http.StatusNotFound)
    36  		default:
    37  			return nil, model.NewAppError("GetGroupByName", "app.select_error", nil, err.Error(), http.StatusInternalServerError)
    38  		}
    39  	}
    40  
    41  	return group, nil
    42  }
    43  
    44  func (a *App) GetGroupByRemoteID(remoteID string, groupSource model.GroupSource) (*model.Group, *model.AppError) {
    45  	group, err := a.Srv().Store.Group().GetByRemoteID(remoteID, groupSource)
    46  	if err != nil {
    47  		var nfErr *store.ErrNotFound
    48  		switch {
    49  		case errors.As(err, &nfErr):
    50  			return nil, model.NewAppError("GetGroupByRemoteID", "app.group.no_rows", nil, nfErr.Error(), http.StatusNotFound)
    51  		default:
    52  			return nil, model.NewAppError("GetGroupByRemoteID", "app.select_error", nil, err.Error(), http.StatusInternalServerError)
    53  		}
    54  	}
    55  
    56  	return group, nil
    57  }
    58  
    59  func (a *App) GetGroupsBySource(groupSource model.GroupSource) ([]*model.Group, *model.AppError) {
    60  	groups, err := a.Srv().Store.Group().GetAllBySource(groupSource)
    61  	if err != nil {
    62  		return nil, model.NewAppError("GetGroupsBySource", "app.select_error", nil, err.Error(), http.StatusInternalServerError)
    63  	}
    64  
    65  	return groups, nil
    66  }
    67  
    68  func (a *App) GetGroupsByUserId(userID string) ([]*model.Group, *model.AppError) {
    69  	groups, err := a.Srv().Store.Group().GetByUser(userID)
    70  	if err != nil {
    71  		return nil, model.NewAppError("GetGroupsByUserId", "app.select_error", nil, err.Error(), http.StatusInternalServerError)
    72  	}
    73  
    74  	return groups, nil
    75  }
    76  
    77  func (a *App) CreateGroup(group *model.Group) (*model.Group, *model.AppError) {
    78  	group, err := a.Srv().Store.Group().Create(group)
    79  	if err != nil {
    80  		var invErr *store.ErrInvalidInput
    81  		var appErr *model.AppError
    82  		switch {
    83  		case errors.As(err, &appErr):
    84  			return nil, appErr
    85  		case errors.As(err, &invErr):
    86  			return nil, model.NewAppError("CreateGroup", "app.group.id.app_error", nil, invErr.Error(), http.StatusBadRequest)
    87  		default:
    88  			return nil, model.NewAppError("CreateGroup", "app.insert_error", nil, err.Error(), http.StatusInternalServerError)
    89  		}
    90  	}
    91  
    92  	return group, nil
    93  }
    94  
    95  func (a *App) UpdateGroup(group *model.Group) (*model.Group, *model.AppError) {
    96  	updatedGroup, err := a.Srv().Store.Group().Update(group)
    97  
    98  	if err == nil {
    99  		messageWs := model.NewWebSocketEvent(model.WEBSOCKET_EVENT_RECEIVED_GROUP, "", "", "", nil)
   100  		messageWs.Add("group", updatedGroup.ToJson())
   101  		a.Publish(messageWs)
   102  	}
   103  
   104  	if err != nil {
   105  		var nfErr *store.ErrNotFound
   106  		var appErr *model.AppError
   107  		switch {
   108  		case errors.As(err, &appErr):
   109  			return nil, appErr
   110  		case errors.As(err, &nfErr):
   111  			return nil, model.NewAppError("UpdateGroup", "app.group.no_rows", nil, nfErr.Error(), http.StatusNotFound)
   112  		default:
   113  			return nil, model.NewAppError("UpdateGroup", "app.select_error", nil, err.Error(), http.StatusInternalServerError)
   114  		}
   115  	}
   116  
   117  	return updatedGroup, nil
   118  }
   119  
   120  func (a *App) DeleteGroup(groupID string) (*model.Group, *model.AppError) {
   121  	deletedGroup, err := a.Srv().Store.Group().Delete(groupID)
   122  
   123  	if err == nil {
   124  		messageWs := model.NewWebSocketEvent(model.WEBSOCKET_EVENT_RECEIVED_GROUP, "", "", "", nil)
   125  		messageWs.Add("group", deletedGroup.ToJson())
   126  		a.Publish(messageWs)
   127  	}
   128  
   129  	if err != nil {
   130  		var nfErr *store.ErrNotFound
   131  		switch {
   132  		case errors.As(err, &nfErr):
   133  			return nil, model.NewAppError("DeleteGroup", "app.group.no_rows", nil, nfErr.Error(), http.StatusNotFound)
   134  		default:
   135  			return nil, model.NewAppError("DeleteGroup", "app.update_error", nil, err.Error(), http.StatusInternalServerError)
   136  		}
   137  	}
   138  
   139  	return deletedGroup, nil
   140  }
   141  
   142  func (a *App) GetGroupMemberCount(groupID string) (int64, *model.AppError) {
   143  	count, err := a.Srv().Store.Group().GetMemberCount(groupID)
   144  	if err != nil {
   145  		return 0, model.NewAppError("GetGroupMemberCount", "app.select_error", nil, err.Error(), http.StatusInternalServerError)
   146  	}
   147  
   148  	return count, nil
   149  }
   150  
   151  func (a *App) GetGroupMemberUsers(groupID string) ([]*model.User, *model.AppError) {
   152  	users, err := a.Srv().Store.Group().GetMemberUsers(groupID)
   153  	if err != nil {
   154  		return nil, model.NewAppError("GetGroupMemberUsers", "app.select_error", nil, err.Error(), http.StatusInternalServerError)
   155  	}
   156  
   157  	return users, nil
   158  }
   159  
   160  func (a *App) GetGroupMemberUsersPage(groupID string, page int, perPage int) ([]*model.User, int, *model.AppError) {
   161  	members, err := a.Srv().Store.Group().GetMemberUsersPage(groupID, page, perPage)
   162  	if err != nil {
   163  		return nil, 0, model.NewAppError("GetGroupMemberUsersPage", "app.select_error", nil, err.Error(), http.StatusInternalServerError)
   164  	}
   165  
   166  	count, appErr := a.GetGroupMemberCount(groupID)
   167  	if appErr != nil {
   168  		return nil, 0, appErr
   169  	}
   170  	return members, int(count), nil
   171  }
   172  
   173  func (a *App) UpsertGroupMember(groupID string, userID string) (*model.GroupMember, *model.AppError) {
   174  	groupMember, err := a.Srv().Store.Group().UpsertMember(groupID, userID)
   175  	if err != nil {
   176  		var invErr *store.ErrInvalidInput
   177  		var appErr *model.AppError
   178  		switch {
   179  		case errors.As(err, &appErr):
   180  			return nil, appErr
   181  		case errors.As(err, &invErr):
   182  			return nil, model.NewAppError("UpsertGroupMember", "app.group.uniqueness_error", nil, invErr.Error(), http.StatusBadRequest)
   183  		default:
   184  			return nil, model.NewAppError("UpsertGroupMember", "app.update_error", nil, err.Error(), http.StatusInternalServerError)
   185  		}
   186  	}
   187  
   188  	return groupMember, nil
   189  }
   190  
   191  func (a *App) DeleteGroupMember(groupID string, userID string) (*model.GroupMember, *model.AppError) {
   192  	groupMember, err := a.Srv().Store.Group().DeleteMember(groupID, userID)
   193  	if err != nil {
   194  		var nfErr *store.ErrNotFound
   195  		switch {
   196  		case errors.As(err, &nfErr):
   197  			return nil, model.NewAppError("DeleteGroupMember", "app.group.no_rows", nil, nfErr.Error(), http.StatusNotFound)
   198  		default:
   199  			return nil, model.NewAppError("DeleteGroupMember", "app.update_error", nil, err.Error(), http.StatusInternalServerError)
   200  		}
   201  	}
   202  
   203  	return groupMember, nil
   204  }
   205  
   206  func (a *App) UpsertGroupSyncable(groupSyncable *model.GroupSyncable) (*model.GroupSyncable, *model.AppError) {
   207  	gs, err := a.Srv().Store.Group().GetGroupSyncable(groupSyncable.GroupId, groupSyncable.SyncableId, groupSyncable.Type)
   208  	var notFoundErr *store.ErrNotFound
   209  	if err != nil && !errors.As(err, &notFoundErr) {
   210  		return nil, model.NewAppError("UpsertGroupSyncable", "app.select_error", nil, err.Error(), http.StatusInternalServerError)
   211  	}
   212  
   213  	// reject the syncable creation if the group isn't already associated to the parent team
   214  	if groupSyncable.Type == model.GroupSyncableTypeChannel {
   215  		channel, nErr := a.Srv().Store.Channel().Get(groupSyncable.SyncableId, true)
   216  		if nErr != nil {
   217  			var nfErr *store.ErrNotFound
   218  			switch {
   219  			case errors.As(nErr, &nfErr):
   220  				return nil, model.NewAppError("UpsertGroupSyncable", "app.channel.get.existing.app_error", nil, nfErr.Error(), http.StatusNotFound)
   221  			default:
   222  				return nil, model.NewAppError("UpsertGroupSyncable", "app.channel.get.find.app_error", nil, nErr.Error(), http.StatusInternalServerError)
   223  			}
   224  		}
   225  
   226  		var team *model.Team
   227  		team, nErr = a.Srv().Store.Team().Get(channel.TeamId)
   228  		if nErr != nil {
   229  			var nfErr *store.ErrNotFound
   230  			switch {
   231  			case errors.As(nErr, &nfErr):
   232  				return nil, model.NewAppError("UpsertGroupSyncable", "app.team.get.find.app_error", nil, nfErr.Error(), http.StatusNotFound)
   233  			default:
   234  				return nil, model.NewAppError("UpsertGroupSyncable", "app.team.get.finding.app_error", nil, nErr.Error(), http.StatusInternalServerError)
   235  			}
   236  		}
   237  		if team.IsGroupConstrained() {
   238  			var teamGroups []*model.GroupWithSchemeAdmin
   239  			teamGroups, err = a.Srv().Store.Group().GetGroupsByTeam(channel.TeamId, model.GroupSearchOpts{})
   240  			if err != nil {
   241  				return nil, model.NewAppError("UpsertGroupSyncable", "app.select_error", nil, err.Error(), http.StatusInternalServerError)
   242  			}
   243  			var permittedGroup bool
   244  			for _, teamGroup := range teamGroups {
   245  				if teamGroup.Group.Id == groupSyncable.GroupId {
   246  					permittedGroup = true
   247  					break
   248  				}
   249  			}
   250  			if !permittedGroup {
   251  				return nil, model.NewAppError("UpsertGroupSyncable", "group_not_associated_to_synced_team", nil, "", http.StatusBadRequest)
   252  			}
   253  		} else {
   254  			_, appErr := a.UpsertGroupSyncable(model.NewGroupTeam(groupSyncable.GroupId, team.Id, groupSyncable.AutoAdd))
   255  			if appErr != nil {
   256  				return nil, appErr
   257  			}
   258  		}
   259  	}
   260  
   261  	if gs == nil {
   262  		gs, err = a.Srv().Store.Group().CreateGroupSyncable(groupSyncable)
   263  		if err != nil {
   264  			var nfErr *store.ErrNotFound
   265  			var appErr *model.AppError
   266  			switch {
   267  			case errors.As(err, &appErr):
   268  				return nil, appErr
   269  			case errors.As(err, &nfErr):
   270  				return nil, model.NewAppError("UpsertGroupSyncable", "store.sql_channel.get.existing.app_error", nil, nfErr.Error(), http.StatusNotFound)
   271  			default:
   272  				return nil, model.NewAppError("UpsertGroupSyncable", "app.insert_error", nil, err.Error(), http.StatusInternalServerError)
   273  			}
   274  		}
   275  	} else {
   276  		gs, err = a.Srv().Store.Group().UpdateGroupSyncable(groupSyncable)
   277  		if err != nil {
   278  			var appErr *model.AppError
   279  			switch {
   280  			case errors.As(err, &appErr):
   281  				return nil, appErr
   282  			default:
   283  				return nil, model.NewAppError("UpsertGroupSyncable", "app.update_error", nil, err.Error(), http.StatusInternalServerError)
   284  			}
   285  		}
   286  	}
   287  
   288  	var messageWs *model.WebSocketEvent
   289  	if gs.Type == model.GroupSyncableTypeTeam {
   290  		messageWs = model.NewWebSocketEvent(model.WEBSOCKET_EVENT_RECEIVED_GROUP_ASSOCIATED_TO_TEAM, gs.SyncableId, "", "", nil)
   291  	} else {
   292  		messageWs = model.NewWebSocketEvent(model.WEBSOCKET_EVENT_RECEIVED_GROUP_ASSOCIATED_TO_CHANNEL, "", gs.SyncableId, "", nil)
   293  	}
   294  	messageWs.Add("group_id", gs.GroupId)
   295  	a.Publish(messageWs)
   296  
   297  	return gs, nil
   298  }
   299  
   300  func (a *App) GetGroupSyncable(groupID string, syncableID string, syncableType model.GroupSyncableType) (*model.GroupSyncable, *model.AppError) {
   301  	group, err := a.Srv().Store.Group().GetGroupSyncable(groupID, syncableID, syncableType)
   302  	if err != nil {
   303  		var nfErr *store.ErrNotFound
   304  		switch {
   305  		case errors.As(err, &nfErr):
   306  			return nil, model.NewAppError("GetGroupSyncable", "app.group.no_rows", nil, nfErr.Error(), http.StatusNotFound)
   307  		default:
   308  			return nil, model.NewAppError("GetGroupSyncable", "app.select_error", nil, err.Error(), http.StatusInternalServerError)
   309  		}
   310  	}
   311  
   312  	return group, nil
   313  }
   314  
   315  func (a *App) GetGroupSyncables(groupID string, syncableType model.GroupSyncableType) ([]*model.GroupSyncable, *model.AppError) {
   316  	groups, err := a.Srv().Store.Group().GetAllGroupSyncablesByGroupId(groupID, syncableType)
   317  	if err != nil {
   318  		return nil, model.NewAppError("GetGroupSyncables", "app.select_error", nil, err.Error(), http.StatusInternalServerError)
   319  	}
   320  
   321  	return groups, nil
   322  }
   323  
   324  func (a *App) UpdateGroupSyncable(groupSyncable *model.GroupSyncable) (*model.GroupSyncable, *model.AppError) {
   325  	if groupSyncable.DeleteAt == 0 {
   326  		// updating a *deleted* GroupSyncable, so no need to ensure the GroupTeam is present (as done in the upsert)
   327  		gs, err := a.Srv().Store.Group().UpdateGroupSyncable(groupSyncable)
   328  		if err != nil {
   329  			var appErr *model.AppError
   330  			switch {
   331  			case errors.As(err, &appErr):
   332  				return nil, appErr
   333  			default:
   334  				return nil, model.NewAppError("UpdateGroupSyncable", "app.update_error", nil, err.Error(), http.StatusInternalServerError)
   335  			}
   336  		}
   337  
   338  		return gs, nil
   339  	}
   340  
   341  	// do an upsert to ensure that there's an associated GroupTeam
   342  	gs, err := a.UpsertGroupSyncable(groupSyncable)
   343  	if err != nil {
   344  		return nil, err
   345  	}
   346  
   347  	return gs, nil
   348  }
   349  
   350  func (a *App) DeleteGroupSyncable(groupID string, syncableID string, syncableType model.GroupSyncableType) (*model.GroupSyncable, *model.AppError) {
   351  	gs, err := a.Srv().Store.Group().DeleteGroupSyncable(groupID, syncableID, syncableType)
   352  	if err != nil {
   353  		var invErr *store.ErrInvalidInput
   354  		var nfErr *store.ErrNotFound
   355  		switch {
   356  		case errors.As(err, &nfErr):
   357  			return nil, model.NewAppError("DeleteGroupSyncable", "app.group.no_rows", nil, nfErr.Error(), http.StatusNotFound)
   358  		case errors.As(err, &invErr):
   359  			return nil, model.NewAppError("DeleteGroupSyncable", "app.group.group_syncable_already_deleted", nil, invErr.Error(), http.StatusBadRequest)
   360  		default:
   361  			return nil, model.NewAppError("DeleteGroupSyncable", "app.update_error", nil, err.Error(), http.StatusInternalServerError)
   362  		}
   363  	}
   364  
   365  	// if a GroupTeam is being deleted delete all associated GroupChannels
   366  	if gs.Type == model.GroupSyncableTypeTeam {
   367  		allGroupChannels, err := a.Srv().Store.Group().GetAllGroupSyncablesByGroupId(gs.GroupId, model.GroupSyncableTypeChannel)
   368  		if err != nil {
   369  			return nil, model.NewAppError("DeleteGroupSyncable", "app.select_error", nil, err.Error(), http.StatusInternalServerError)
   370  		}
   371  
   372  		for _, groupChannel := range allGroupChannels {
   373  			_, err = a.Srv().Store.Group().DeleteGroupSyncable(groupChannel.GroupId, groupChannel.SyncableId, groupChannel.Type)
   374  			if err != nil {
   375  				var invErr *store.ErrInvalidInput
   376  				var nfErr *store.ErrNotFound
   377  				switch {
   378  				case errors.As(err, &nfErr):
   379  					return nil, model.NewAppError("DeleteGroupSyncable", "app.group.no_rows", nil, nfErr.Error(), http.StatusNotFound)
   380  				case errors.As(err, &invErr):
   381  					return nil, model.NewAppError("DeleteGroupSyncable", "app.group.group_syncable_already_deleted", nil, invErr.Error(), http.StatusBadRequest)
   382  				default:
   383  					return nil, model.NewAppError("DeleteGroupSyncable", "app.update_error", nil, err.Error(), http.StatusInternalServerError)
   384  				}
   385  			}
   386  		}
   387  	}
   388  
   389  	var messageWs *model.WebSocketEvent
   390  	if gs.Type == model.GroupSyncableTypeTeam {
   391  		messageWs = model.NewWebSocketEvent(model.WEBSOCKET_EVENT_RECEIVED_GROUP_NOT_ASSOCIATED_TO_TEAM, gs.SyncableId, "", "", nil)
   392  	} else {
   393  		messageWs = model.NewWebSocketEvent(model.WEBSOCKET_EVENT_RECEIVED_GROUP_NOT_ASSOCIATED_TO_CHANNEL, "", gs.SyncableId, "", nil)
   394  	}
   395  
   396  	messageWs.Add("group_id", gs.GroupId)
   397  	a.Publish(messageWs)
   398  
   399  	return gs, nil
   400  }
   401  
   402  func (a *App) TeamMembersToAdd(since int64, teamID *string) ([]*model.UserTeamIDPair, *model.AppError) {
   403  	userTeams, err := a.Srv().Store.Group().TeamMembersToAdd(since, teamID)
   404  	if err != nil {
   405  		return nil, model.NewAppError("TeamMembersToAdd", "app.select_error", nil, err.Error(), http.StatusInternalServerError)
   406  	}
   407  
   408  	return userTeams, nil
   409  }
   410  
   411  func (a *App) ChannelMembersToAdd(since int64, channelID *string) ([]*model.UserChannelIDPair, *model.AppError) {
   412  	userChannels, err := a.Srv().Store.Group().ChannelMembersToAdd(since, channelID)
   413  	if err != nil {
   414  		return nil, model.NewAppError("ChannelMembersToAdd", "app.select_error", nil, err.Error(), http.StatusInternalServerError)
   415  	}
   416  
   417  	return userChannels, nil
   418  }
   419  
   420  func (a *App) TeamMembersToRemove(teamID *string) ([]*model.TeamMember, *model.AppError) {
   421  	teamMembers, err := a.Srv().Store.Group().TeamMembersToRemove(teamID)
   422  	if err != nil {
   423  		return nil, model.NewAppError("TeamMembersToRemove", "app.select_error", nil, err.Error(), http.StatusInternalServerError)
   424  	}
   425  
   426  	return teamMembers, nil
   427  }
   428  
   429  func (a *App) ChannelMembersToRemove(teamID *string) ([]*model.ChannelMember, *model.AppError) {
   430  	channelMembers, err := a.Srv().Store.Group().ChannelMembersToRemove(teamID)
   431  	if err != nil {
   432  		return nil, model.NewAppError("ChannelMembersToRemove", "app.select_error", nil, err.Error(), http.StatusInternalServerError)
   433  	}
   434  
   435  	return channelMembers, nil
   436  }
   437  
   438  func (a *App) GetGroupsByChannel(channelId string, opts model.GroupSearchOpts) ([]*model.GroupWithSchemeAdmin, int, *model.AppError) {
   439  	groups, err := a.Srv().Store.Group().GetGroupsByChannel(channelId, opts)
   440  	if err != nil {
   441  		return nil, 0, model.NewAppError("GetGroupsByChannel", "app.select_error", nil, err.Error(), http.StatusInternalServerError)
   442  	}
   443  
   444  	count, err := a.Srv().Store.Group().CountGroupsByChannel(channelId, opts)
   445  	if err != nil {
   446  		return nil, 0, model.NewAppError("GetGroupsByChannel", "app.select_error", nil, err.Error(), http.StatusInternalServerError)
   447  	}
   448  
   449  	return groups, int(count), nil
   450  }
   451  
   452  // GetGroupsByTeam returns the paged list and the total count of group associated to the given team.
   453  func (a *App) GetGroupsByTeam(teamID string, opts model.GroupSearchOpts) ([]*model.GroupWithSchemeAdmin, int, *model.AppError) {
   454  	groups, err := a.Srv().Store.Group().GetGroupsByTeam(teamID, opts)
   455  	if err != nil {
   456  		return nil, 0, model.NewAppError("GetGroupsByTeam", "app.select_error", nil, err.Error(), http.StatusInternalServerError)
   457  	}
   458  
   459  	count, err := a.Srv().Store.Group().CountGroupsByTeam(teamID, opts)
   460  	if err != nil {
   461  		return nil, 0, model.NewAppError("GetGroupsByTeam", "app.select_error", nil, err.Error(), http.StatusInternalServerError)
   462  	}
   463  
   464  	return groups, int(count), nil
   465  }
   466  
   467  func (a *App) GetGroupsAssociatedToChannelsByTeam(teamID string, opts model.GroupSearchOpts) (map[string][]*model.GroupWithSchemeAdmin, *model.AppError) {
   468  	groupsAssociatedByChannelId, err := a.Srv().Store.Group().GetGroupsAssociatedToChannelsByTeam(teamID, opts)
   469  	if err != nil {
   470  		return nil, model.NewAppError("GetGroupsAssociatedToChannelsByTeam", "app.select_error", nil, err.Error(), http.StatusInternalServerError)
   471  	}
   472  
   473  	return groupsAssociatedByChannelId, nil
   474  }
   475  
   476  func (a *App) GetGroups(page, perPage int, opts model.GroupSearchOpts) ([]*model.Group, *model.AppError) {
   477  	groups, err := a.Srv().Store.Group().GetGroups(page, perPage, opts)
   478  	if err != nil {
   479  		return nil, model.NewAppError("GetGroups", "app.select_error", nil, err.Error(), http.StatusInternalServerError)
   480  	}
   481  
   482  	return groups, nil
   483  }
   484  
   485  // TeamMembersMinusGroupMembers returns the set of users on the given team minus the set of users in the given
   486  // groups.
   487  //
   488  // The result can be used, for example, to determine the set of users who would be removed from a team if the team
   489  // were group-constrained with the given groups.
   490  func (a *App) TeamMembersMinusGroupMembers(teamID string, groupIDs []string, page, perPage int) ([]*model.UserWithGroups, int64, *model.AppError) {
   491  	users, err := a.Srv().Store.Group().TeamMembersMinusGroupMembers(teamID, groupIDs, page, perPage)
   492  	if err != nil {
   493  		return nil, 0, model.NewAppError("TeamMembersMinusGroupMembers", "app.select_error", nil, err.Error(), http.StatusInternalServerError)
   494  	}
   495  
   496  	// parse all group ids of all users
   497  	allUsersGroupIDMap := map[string]bool{}
   498  	for _, user := range users {
   499  		for _, groupID := range user.GetGroupIDs() {
   500  			allUsersGroupIDMap[groupID] = true
   501  		}
   502  	}
   503  
   504  	// create a slice of distinct group ids
   505  	var allUsersGroupIDSlice []string
   506  	for key := range allUsersGroupIDMap {
   507  		allUsersGroupIDSlice = append(allUsersGroupIDSlice, key)
   508  	}
   509  
   510  	// retrieve groups from DB
   511  	groups, appErr := a.GetGroupsByIDs(allUsersGroupIDSlice)
   512  	if appErr != nil {
   513  		return nil, 0, appErr
   514  	}
   515  
   516  	// map groups by id
   517  	groupMap := map[string]*model.Group{}
   518  	for _, group := range groups {
   519  		groupMap[group.Id] = group
   520  	}
   521  
   522  	// populate each instance's groups field
   523  	for _, user := range users {
   524  		user.Groups = []*model.Group{}
   525  		for _, groupID := range user.GetGroupIDs() {
   526  			group, ok := groupMap[groupID]
   527  			if ok {
   528  				user.Groups = append(user.Groups, group)
   529  			}
   530  		}
   531  	}
   532  
   533  	totalCount, err := a.Srv().Store.Group().CountTeamMembersMinusGroupMembers(teamID, groupIDs)
   534  	if err != nil {
   535  		return nil, 0, model.NewAppError("TeamMembersMinusGroupMembers", "app.select_error", nil, err.Error(), http.StatusInternalServerError)
   536  	}
   537  	return users, totalCount, nil
   538  }
   539  
   540  func (a *App) GetGroupsByIDs(groupIDs []string) ([]*model.Group, *model.AppError) {
   541  	groups, err := a.Srv().Store.Group().GetByIDs(groupIDs)
   542  	if err != nil {
   543  		return nil, model.NewAppError("GetGroupsByIDs", "app.select_error", nil, err.Error(), http.StatusInternalServerError)
   544  	}
   545  
   546  	return groups, nil
   547  }
   548  
   549  // ChannelMembersMinusGroupMembers returns the set of users in the given channel minus the set of users in the given
   550  // groups.
   551  //
   552  // The result can be used, for example, to determine the set of users who would be removed from a channel if the
   553  // channel were group-constrained with the given groups.
   554  func (a *App) ChannelMembersMinusGroupMembers(channelID string, groupIDs []string, page, perPage int) ([]*model.UserWithGroups, int64, *model.AppError) {
   555  	users, err := a.Srv().Store.Group().ChannelMembersMinusGroupMembers(channelID, groupIDs, page, perPage)
   556  	if err != nil {
   557  		return nil, 0, model.NewAppError("ChannelMembersMinusGroupMembers", "app.select_error", nil, err.Error(), http.StatusInternalServerError)
   558  	}
   559  
   560  	// parse all group ids of all users
   561  	allUsersGroupIDMap := map[string]bool{}
   562  	for _, user := range users {
   563  		for _, groupID := range user.GetGroupIDs() {
   564  			allUsersGroupIDMap[groupID] = true
   565  		}
   566  	}
   567  
   568  	// create a slice of distinct group ids
   569  	var allUsersGroupIDSlice []string
   570  	for key := range allUsersGroupIDMap {
   571  		allUsersGroupIDSlice = append(allUsersGroupIDSlice, key)
   572  	}
   573  
   574  	// retrieve groups from DB
   575  	groups, appErr := a.GetGroupsByIDs(allUsersGroupIDSlice)
   576  	if appErr != nil {
   577  		return nil, 0, appErr
   578  	}
   579  
   580  	// map groups by id
   581  	groupMap := map[string]*model.Group{}
   582  	for _, group := range groups {
   583  		groupMap[group.Id] = group
   584  	}
   585  
   586  	// populate each instance's groups field
   587  	for _, user := range users {
   588  		user.Groups = []*model.Group{}
   589  		for _, groupID := range user.GetGroupIDs() {
   590  			group, ok := groupMap[groupID]
   591  			if ok {
   592  				user.Groups = append(user.Groups, group)
   593  			}
   594  		}
   595  	}
   596  
   597  	totalCount, err := a.Srv().Store.Group().CountChannelMembersMinusGroupMembers(channelID, groupIDs)
   598  	if err != nil {
   599  		return nil, 0, model.NewAppError("ChannelMembersMinusGroupMembers", "app.select_error", nil, err.Error(), http.StatusInternalServerError)
   600  	}
   601  	return users, totalCount, nil
   602  }
   603  
   604  // UserIsInAdminRoleGroup returns true at least one of the user's groups are configured to set the members as
   605  // admins in the given syncable.
   606  func (a *App) UserIsInAdminRoleGroup(userID, syncableID string, syncableType model.GroupSyncableType) (bool, *model.AppError) {
   607  	groupIDs, err := a.Srv().Store.Group().AdminRoleGroupsForSyncableMember(userID, syncableID, syncableType)
   608  	if err != nil {
   609  		return false, model.NewAppError("UserIsInAdminRoleGroup", "app.select_error", nil, err.Error(), http.StatusInternalServerError)
   610  	}
   611  
   612  	if len(groupIDs) == 0 {
   613  		return false, nil
   614  	}
   615  
   616  	return true, nil
   617  }