github.com/mad-app/mattermost-server@v5.11.1+incompatible/store/sqlstore/group_supplier.go (about)

     1  // Copyright (c) 2018-present Mattermost, Inc. All Rights Reserved.
     2  // See License.txt for license information.
     3  
     4  package sqlstore
     5  
     6  import (
     7  	"context"
     8  	"database/sql"
     9  	"fmt"
    10  	"net/http"
    11  
    12  	"github.com/mattermost/mattermost-server/model"
    13  	"github.com/mattermost/mattermost-server/store"
    14  )
    15  
    16  type groupTeam struct {
    17  	model.GroupSyncable
    18  	TeamId string `db:"TeamId"`
    19  }
    20  
    21  type groupChannel struct {
    22  	model.GroupSyncable
    23  	ChannelId string `db:"ChannelId"`
    24  }
    25  
    26  type groupTeamJoin struct {
    27  	groupTeam
    28  	TeamDisplayName string `db:"TeamDisplayName"`
    29  	TeamType        string `db:"TeamType"`
    30  }
    31  
    32  type groupChannelJoin struct {
    33  	groupChannel
    34  	ChannelDisplayName string `db:"ChannelDisplayName"`
    35  	TeamDisplayName    string `db:"TeamDisplayName"`
    36  	TeamType           string `db:"TeamType"`
    37  	ChannelType        string `db:"ChannelType"`
    38  	TeamID             string `db:"TeamId"`
    39  }
    40  
    41  func initSqlSupplierGroups(sqlStore SqlStore) {
    42  	for _, db := range sqlStore.GetAllConns() {
    43  		groups := db.AddTableWithName(model.Group{}, "UserGroups").SetKeys(false, "Id")
    44  		groups.ColMap("Id").SetMaxSize(26)
    45  		groups.ColMap("Name").SetMaxSize(model.GroupNameMaxLength).SetUnique(true)
    46  		groups.ColMap("DisplayName").SetMaxSize(model.GroupDisplayNameMaxLength)
    47  		groups.ColMap("Description").SetMaxSize(model.GroupDescriptionMaxLength)
    48  		groups.ColMap("Source").SetMaxSize(model.GroupSourceMaxLength)
    49  		groups.ColMap("RemoteId").SetMaxSize(model.GroupRemoteIDMaxLength)
    50  		groups.SetUniqueTogether("Source", "RemoteId")
    51  
    52  		groupMembers := db.AddTableWithName(model.GroupMember{}, "GroupMembers").SetKeys(false, "GroupId", "UserId")
    53  		groupMembers.ColMap("GroupId").SetMaxSize(26)
    54  		groupMembers.ColMap("UserId").SetMaxSize(26)
    55  
    56  		groupTeams := db.AddTableWithName(groupTeam{}, "GroupTeams").SetKeys(false, "GroupId", "TeamId")
    57  		groupTeams.ColMap("GroupId").SetMaxSize(26)
    58  		groupTeams.ColMap("TeamId").SetMaxSize(26)
    59  
    60  		groupChannels := db.AddTableWithName(groupChannel{}, "GroupChannels").SetKeys(false, "GroupId", "ChannelId")
    61  		groupChannels.ColMap("GroupId").SetMaxSize(26)
    62  		groupChannels.ColMap("ChannelId").SetMaxSize(26)
    63  	}
    64  }
    65  
    66  func (s *SqlSupplier) CreateIndexesIfNotExistsGroups() {
    67  	s.CreateIndexIfNotExists("idx_groupmembers_create_at", "GroupMembers", "CreateAt")
    68  	s.CreateIndexIfNotExists("idx_usergroups_remote_id", "UserGroups", "RemoteId")
    69  	s.CreateIndexIfNotExists("idx_usergroups_delete_at", "UserGroups", "DeleteAt")
    70  }
    71  
    72  func (s *SqlSupplier) GroupCreate(ctx context.Context, group *model.Group, hints ...store.LayeredStoreHint) *store.LayeredStoreSupplierResult {
    73  	result := store.NewSupplierResult()
    74  
    75  	if len(group.Id) != 0 {
    76  		result.Err = model.NewAppError("SqlGroupStore.GroupCreate", "model.group.id.app_error", nil, "", http.StatusBadRequest)
    77  		return result
    78  	}
    79  
    80  	if err := group.IsValidForCreate(); err != nil {
    81  		result.Err = err
    82  		return result
    83  	}
    84  
    85  	group.Id = model.NewId()
    86  	group.CreateAt = model.GetMillis()
    87  	group.UpdateAt = group.CreateAt
    88  
    89  	if err := s.GetMaster().Insert(group); err != nil {
    90  		if IsUniqueConstraintError(err, []string{"Name", "groups_name_key"}) {
    91  			result.Err = model.NewAppError("SqlGroupStore.GroupCreate", "store.sql_group.unique_constraint", nil, err.Error(), http.StatusInternalServerError)
    92  		} else {
    93  			result.Err = model.NewAppError("SqlGroupStore.GroupCreate", "store.insert_error", nil, err.Error(), http.StatusInternalServerError)
    94  		}
    95  		return result
    96  	}
    97  
    98  	result.Data = group
    99  	return result
   100  }
   101  
   102  func (s *SqlSupplier) GroupGet(ctx context.Context, groupId string, hints ...store.LayeredStoreHint) *store.LayeredStoreSupplierResult {
   103  	result := store.NewSupplierResult()
   104  
   105  	var group *model.Group
   106  	if err := s.GetReplica().SelectOne(&group, "SELECT * from UserGroups WHERE Id = :Id", map[string]interface{}{"Id": groupId}); err != nil {
   107  		if err == sql.ErrNoRows {
   108  			result.Err = model.NewAppError("SqlGroupStore.GroupGet", "store.sql_group.no_rows", nil, err.Error(), http.StatusNotFound)
   109  		} else {
   110  			result.Err = model.NewAppError("SqlGroupStore.GroupGet", "store.select_error", nil, err.Error(), http.StatusInternalServerError)
   111  		}
   112  		return result
   113  	}
   114  
   115  	result.Data = group
   116  	return result
   117  }
   118  
   119  func (s *SqlSupplier) GroupGetByRemoteID(ctx context.Context, remoteID string, groupSource model.GroupSource, hints ...store.LayeredStoreHint) *store.LayeredStoreSupplierResult {
   120  	result := store.NewSupplierResult()
   121  
   122  	var group *model.Group
   123  	if err := s.GetReplica().SelectOne(&group, "SELECT * from UserGroups WHERE RemoteId = :RemoteId AND Source = :Source", map[string]interface{}{"RemoteId": remoteID, "Source": groupSource}); err != nil {
   124  		if err == sql.ErrNoRows {
   125  			result.Err = model.NewAppError("SqlGroupStore.GroupGetByRemoteID", "store.sql_group.no_rows", nil, err.Error(), http.StatusNotFound)
   126  		} else {
   127  			result.Err = model.NewAppError("SqlGroupStore.GroupGetByRemoteID", "store.select_error", nil, err.Error(), http.StatusInternalServerError)
   128  		}
   129  		return result
   130  	}
   131  
   132  	result.Data = group
   133  	return result
   134  }
   135  
   136  func (s *SqlSupplier) GroupGetAllBySource(ctx context.Context, groupSource model.GroupSource, hints ...store.LayeredStoreHint) *store.LayeredStoreSupplierResult {
   137  	result := store.NewSupplierResult()
   138  
   139  	var groups []*model.Group
   140  
   141  	if _, err := s.GetReplica().Select(&groups, "SELECT * from UserGroups WHERE DeleteAt = 0 AND Source = :Source", map[string]interface{}{"Source": groupSource}); err != nil {
   142  		result.Err = model.NewAppError("SqlGroupStore.GroupGetAllBySource", "store.select_error", nil, err.Error(), http.StatusInternalServerError)
   143  		return result
   144  	}
   145  
   146  	result.Data = groups
   147  
   148  	return result
   149  }
   150  
   151  func (s *SqlSupplier) GroupUpdate(ctx context.Context, group *model.Group, hints ...store.LayeredStoreHint) *store.LayeredStoreSupplierResult {
   152  	result := store.NewSupplierResult()
   153  
   154  	var retrievedGroup *model.Group
   155  	if err := s.GetMaster().SelectOne(&retrievedGroup, "SELECT * FROM UserGroups WHERE Id = :Id", map[string]interface{}{"Id": group.Id}); err != nil {
   156  		if err == sql.ErrNoRows {
   157  			result.Err = model.NewAppError("SqlGroupStore.GroupUpdate", "store.sql_group.no_rows", nil, "id="+group.Id+","+err.Error(), http.StatusNotFound)
   158  		} else {
   159  			result.Err = model.NewAppError("SqlGroupStore.GroupUpdate", "store.select_error", nil, "id="+group.Id+","+err.Error(), http.StatusInternalServerError)
   160  		}
   161  		return result
   162  	}
   163  
   164  	// If updating DeleteAt it can only be to 0
   165  	if group.DeleteAt != retrievedGroup.DeleteAt && group.DeleteAt != 0 {
   166  		result.Err = model.NewAppError("SqlGroupStore.GroupUpdate", "model.group.delete_at.app_error", nil, "", http.StatusInternalServerError)
   167  		return result
   168  	}
   169  
   170  	// Reset these properties, don't update them based on input
   171  	group.CreateAt = retrievedGroup.CreateAt
   172  	group.UpdateAt = model.GetMillis()
   173  
   174  	if err := group.IsValidForUpdate(); err != nil {
   175  		result.Err = err
   176  		return result
   177  	}
   178  
   179  	rowsChanged, err := s.GetMaster().Update(group)
   180  	if err != nil {
   181  		result.Err = model.NewAppError("SqlGroupStore.GroupUpdate", "store.update_error", nil, err.Error(), http.StatusInternalServerError)
   182  		return result
   183  	}
   184  	if rowsChanged != 1 {
   185  		result.Err = model.NewAppError("SqlGroupStore.GroupUpdate", "store.sql_group.no_rows_changed", nil, "", http.StatusInternalServerError)
   186  		return result
   187  	}
   188  
   189  	result.Data = group
   190  	return result
   191  }
   192  
   193  func (s *SqlSupplier) GroupDelete(ctx context.Context, groupID string, hints ...store.LayeredStoreHint) *store.LayeredStoreSupplierResult {
   194  	result := store.NewSupplierResult()
   195  
   196  	var group *model.Group
   197  	if err := s.GetReplica().SelectOne(&group, "SELECT * from UserGroups WHERE Id = :Id AND DeleteAt = 0", map[string]interface{}{"Id": groupID}); err != nil {
   198  		if err == sql.ErrNoRows {
   199  			result.Err = model.NewAppError("SqlGroupStore.GroupDelete", "store.sql_group.no_rows", nil, "Id="+groupID+", "+err.Error(), http.StatusNotFound)
   200  		} else {
   201  			result.Err = model.NewAppError("SqlGroupStore.GroupDelete", "store.select_error", nil, err.Error(), http.StatusInternalServerError)
   202  		}
   203  
   204  		return result
   205  	}
   206  
   207  	time := model.GetMillis()
   208  	group.DeleteAt = time
   209  	group.UpdateAt = time
   210  
   211  	if _, err := s.GetMaster().Update(group); err != nil {
   212  		result.Err = model.NewAppError("SqlGroupStore.GroupDelete", "store.update_error", nil, err.Error(), http.StatusInternalServerError)
   213  	}
   214  
   215  	result.Data = group
   216  	return result
   217  }
   218  
   219  func (s *SqlSupplier) GroupGetMemberUsers(stc context.Context, groupID string, hints ...store.LayeredStoreHint) *store.LayeredStoreSupplierResult {
   220  	result := store.NewSupplierResult()
   221  
   222  	var groupMembers []*model.User
   223  
   224  	query := `
   225  		SELECT 
   226  			Users.* 
   227  		FROM 
   228  			GroupMembers 
   229  			JOIN Users ON Users.Id = GroupMembers.UserId
   230  		WHERE 
   231  			GroupMembers.DeleteAt = 0 
   232  			AND Users.DeleteAt = 0
   233  			AND GroupId = :GroupId`
   234  
   235  	if _, err := s.GetReplica().Select(&groupMembers, query, map[string]interface{}{"GroupId": groupID}); err != nil {
   236  		result.Err = model.NewAppError("SqlGroupStore.GroupGetAllBySource", "store.select_error", nil, err.Error(), http.StatusInternalServerError)
   237  		return result
   238  	}
   239  
   240  	result.Data = groupMembers
   241  
   242  	return result
   243  }
   244  
   245  func (s *SqlSupplier) GroupGetMemberUsersPage(stc context.Context, groupID string, offset int, limit int, hints ...store.LayeredStoreHint) *store.LayeredStoreSupplierResult {
   246  	result := store.NewSupplierResult()
   247  
   248  	var groupMembers []*model.User
   249  
   250  	query := `
   251  		SELECT 
   252  			Users.* 
   253  		FROM 
   254  			GroupMembers 
   255  			JOIN Users ON Users.Id = GroupMembers.UserId
   256  		WHERE 
   257  			GroupMembers.DeleteAt = 0 
   258  			AND Users.DeleteAt = 0
   259  			AND GroupId = :GroupId
   260  		ORDER BY
   261  			GroupMembers.CreateAt DESC
   262  		LIMIT
   263  			:Limit
   264  		OFFSET
   265  			:Offset`
   266  
   267  	if _, err := s.GetReplica().Select(&groupMembers, query, map[string]interface{}{"GroupId": groupID, "Limit": limit, "Offset": offset}); err != nil {
   268  		result.Err = model.NewAppError("SqlGroupStore.GroupGetMemberUsersPage", "store.select_error", nil, err.Error(), http.StatusInternalServerError)
   269  		return result
   270  	}
   271  
   272  	result.Data = groupMembers
   273  
   274  	return result
   275  }
   276  
   277  func (s *SqlSupplier) GroupGetMemberCount(stc context.Context, groupID string, hints ...store.LayeredStoreHint) *store.LayeredStoreSupplierResult {
   278  	result := store.NewSupplierResult()
   279  
   280  	var count int64
   281  	var err error
   282  
   283  	query := `
   284  		SELECT 
   285  			count(*) 
   286  		FROM 
   287  			GroupMembers 
   288  		WHERE 
   289  			GroupMembers.GroupId = :GroupId`
   290  
   291  	if count, err = s.GetReplica().SelectInt(query, map[string]interface{}{"GroupId": groupID}); err != nil {
   292  		result.Err = model.NewAppError("SqlGroupStore.GroupGetMemberUsersPage", "store.select_error", nil, err.Error(), http.StatusInternalServerError)
   293  		return result
   294  	}
   295  
   296  	result.Data = count
   297  
   298  	return result
   299  }
   300  
   301  func (s *SqlSupplier) GroupCreateOrRestoreMember(ctx context.Context, groupID string, userID string, hints ...store.LayeredStoreHint) *store.LayeredStoreSupplierResult {
   302  	result := store.NewSupplierResult()
   303  
   304  	member := &model.GroupMember{
   305  		GroupId:  groupID,
   306  		UserId:   userID,
   307  		CreateAt: model.GetMillis(),
   308  	}
   309  
   310  	if result.Err = member.IsValid(); result.Err != nil {
   311  		return result
   312  	}
   313  
   314  	var retrievedGroup *model.Group
   315  	if err := s.GetMaster().SelectOne(&retrievedGroup, "SELECT * FROM UserGroups WHERE Id = :Id", map[string]interface{}{"Id": groupID}); err != nil {
   316  		result.Err = model.NewAppError("SqlGroupStore.GroupCreateOrRestoreMember", "store.insert_error", nil, "group_id="+member.GroupId+"user_id="+member.UserId+","+err.Error(), http.StatusInternalServerError)
   317  		return result
   318  	}
   319  
   320  	var retrievedMember *model.GroupMember
   321  	if err := s.GetMaster().SelectOne(&retrievedMember, "SELECT * FROM GroupMembers WHERE GroupId = :GroupId AND UserId = :UserId", map[string]interface{}{"GroupId": member.GroupId, "UserId": member.UserId}); err != nil {
   322  		if err != sql.ErrNoRows {
   323  			result.Err = model.NewAppError("SqlGroupStore.GroupCreateOrRestoreMember", "store.select_error", nil, "group_id="+member.GroupId+"user_id="+member.UserId+","+err.Error(), http.StatusInternalServerError)
   324  			return result
   325  		}
   326  	}
   327  
   328  	if retrievedMember != nil && retrievedMember.DeleteAt == 0 {
   329  		result.Err = model.NewAppError("SqlGroupStore.GroupCreateOrRestoreMember", "store.sql_group.uniqueness_error", nil, "group_id="+member.GroupId+", user_id="+member.UserId, http.StatusBadRequest)
   330  		return result
   331  	}
   332  
   333  	if retrievedMember == nil {
   334  		if err := s.GetMaster().Insert(member); err != nil {
   335  			if IsUniqueConstraintError(err, []string{"GroupId", "UserId", "groupmembers_pkey", "PRIMARY"}) {
   336  				result.Err = model.NewAppError("SqlGroupStore.GroupCreateOrRestoreMember", "store.sql_group.uniqueness_error", nil, "group_id="+member.GroupId+", user_id="+member.UserId+", "+err.Error(), http.StatusBadRequest)
   337  				return result
   338  			}
   339  			result.Err = model.NewAppError("SqlGroupStore.GroupCreateOrRestoreMember", "store.insert_error", nil, "group_id="+member.GroupId+", user_id="+member.UserId+", "+err.Error(), http.StatusInternalServerError)
   340  			return result
   341  		}
   342  	} else {
   343  		member.DeleteAt = 0
   344  		var rowsChanged int64
   345  		var err error
   346  		if rowsChanged, err = s.GetMaster().Update(member); err != nil {
   347  			result.Err = model.NewAppError("SqlGroupStore.GroupCreateOrRestoreMember", "store.update_error", nil, "group_id="+member.GroupId+", user_id="+member.UserId+", "+err.Error(), http.StatusInternalServerError)
   348  			return result
   349  		}
   350  		if rowsChanged != 1 {
   351  			result.Err = model.NewAppError("SqlGroupStore.GroupCreateOrRestoreMember", "store.sql_group.no_rows_changed", nil, "", http.StatusInternalServerError)
   352  			return result
   353  		}
   354  	}
   355  
   356  	result.Data = member
   357  	return result
   358  }
   359  
   360  func (s *SqlSupplier) GroupDeleteMember(ctx context.Context, groupID string, userID string, hints ...store.LayeredStoreHint) *store.LayeredStoreSupplierResult {
   361  	result := store.NewSupplierResult()
   362  
   363  	var retrievedMember *model.GroupMember
   364  	if err := s.GetMaster().SelectOne(&retrievedMember, "SELECT * FROM GroupMembers WHERE GroupId = :GroupId AND UserId = :UserId AND DeleteAt = 0", map[string]interface{}{"GroupId": groupID, "UserId": userID}); err != nil {
   365  		if err == sql.ErrNoRows {
   366  			result.Err = model.NewAppError("SqlGroupStore.GroupDeleteMember", "store.sql_group.no_rows", nil, "group_id="+groupID+"user_id="+userID+","+err.Error(), http.StatusNotFound)
   367  			return result
   368  		}
   369  		result.Err = model.NewAppError("SqlGroupStore.GroupDeleteMember", "store.select_error", nil, "group_id="+groupID+"user_id="+userID+","+err.Error(), http.StatusInternalServerError)
   370  		return result
   371  	}
   372  
   373  	retrievedMember.DeleteAt = model.GetMillis()
   374  
   375  	if _, err := s.GetMaster().Update(retrievedMember); err != nil {
   376  		result.Err = model.NewAppError("SqlGroupStore.GroupDeleteMember", "store.update_error", nil, err.Error(), http.StatusInternalServerError)
   377  		return result
   378  	}
   379  
   380  	result.Data = retrievedMember
   381  	return result
   382  }
   383  
   384  func (s *SqlSupplier) GroupCreateGroupSyncable(ctx context.Context, groupSyncable *model.GroupSyncable, hints ...store.LayeredStoreHint) *store.LayeredStoreSupplierResult {
   385  	result := store.NewSupplierResult()
   386  
   387  	if err := groupSyncable.IsValid(); err != nil {
   388  		result.Err = err
   389  		return result
   390  	}
   391  
   392  	// Reset values that shouldn't be updatable by parameter
   393  	groupSyncable.DeleteAt = 0
   394  	groupSyncable.CreateAt = model.GetMillis()
   395  	groupSyncable.UpdateAt = groupSyncable.CreateAt
   396  
   397  	var err error
   398  
   399  	switch groupSyncable.Type {
   400  	case model.GroupSyncableTypeTeam:
   401  		teamResult := <-s.Team().Get(groupSyncable.SyncableId)
   402  		if teamResult.Err != nil {
   403  			result.Err = teamResult.Err
   404  			return result
   405  		}
   406  
   407  		err = s.GetMaster().Insert(groupSyncableToGroupTeam(groupSyncable))
   408  	case model.GroupSyncableTypeChannel:
   409  		channelResult := <-s.Channel().Get(groupSyncable.SyncableId, false)
   410  		if channelResult.Err != nil {
   411  			result.Err = channelResult.Err
   412  			return result
   413  		}
   414  
   415  		err = s.GetMaster().Insert(groupSyncableToGroupChannel(groupSyncable))
   416  	default:
   417  		result.Err = model.NewAppError("SqlGroupStore.GroupCreateGroupSyncable", "model.group_syncable.type.app_error", nil, "group_id="+groupSyncable.GroupId+", syncable_id="+groupSyncable.SyncableId+", "+err.Error(), http.StatusInternalServerError)
   418  		return result
   419  	}
   420  
   421  	if err != nil {
   422  		result.Err = model.NewAppError("SqlGroupStore.GroupCreateGroupSyncable", "store.insert_error", nil, "group_id="+groupSyncable.GroupId+", syncable_id="+groupSyncable.SyncableId+", "+err.Error(), http.StatusInternalServerError)
   423  		return result
   424  	}
   425  
   426  	result.Data = groupSyncable
   427  	return result
   428  }
   429  
   430  func (s *SqlSupplier) GroupGetGroupSyncable(ctx context.Context, groupID string, syncableID string, syncableType model.GroupSyncableType, hints ...store.LayeredStoreHint) *store.LayeredStoreSupplierResult {
   431  	result := store.NewSupplierResult()
   432  
   433  	groupSyncable, err := s.getGroupSyncable(groupID, syncableID, syncableType)
   434  	if err != nil {
   435  		if err == sql.ErrNoRows {
   436  			result.Err = model.NewAppError("SqlGroupStore.GroupGetGroupSyncable", "store.sql_group.no_rows", nil, err.Error(), http.StatusNotFound)
   437  		} else {
   438  			result.Err = model.NewAppError("SqlGroupStore.GroupGetGroupSyncable", "store.select_error", nil, err.Error(), http.StatusInternalServerError)
   439  		}
   440  		return result
   441  	}
   442  
   443  	result.Data = groupSyncable
   444  
   445  	return result
   446  }
   447  
   448  func (s *SqlSupplier) getGroupSyncable(groupID string, syncableID string, syncableType model.GroupSyncableType) (*model.GroupSyncable, error) {
   449  	var err error
   450  	var result interface{}
   451  
   452  	switch syncableType {
   453  	case model.GroupSyncableTypeTeam:
   454  		result, err = s.GetMaster().Get(groupTeam{}, groupID, syncableID)
   455  	case model.GroupSyncableTypeChannel:
   456  		result, err = s.GetMaster().Get(groupChannel{}, groupID, syncableID)
   457  	}
   458  
   459  	if err != nil {
   460  		return nil, err
   461  	}
   462  
   463  	if result == nil {
   464  		return nil, sql.ErrNoRows
   465  	}
   466  
   467  	groupSyncable := model.GroupSyncable{}
   468  	switch syncableType {
   469  	case model.GroupSyncableTypeTeam:
   470  		groupTeam := result.(*groupTeam)
   471  		groupSyncable.SyncableId = groupTeam.TeamId
   472  		groupSyncable.GroupId = groupTeam.GroupId
   473  		groupSyncable.AutoAdd = groupTeam.AutoAdd
   474  		groupSyncable.CreateAt = groupTeam.CreateAt
   475  		groupSyncable.DeleteAt = groupTeam.DeleteAt
   476  		groupSyncable.UpdateAt = groupTeam.UpdateAt
   477  		groupSyncable.Type = syncableType
   478  	case model.GroupSyncableTypeChannel:
   479  		groupChannel := result.(*groupChannel)
   480  		groupSyncable.SyncableId = groupChannel.ChannelId
   481  		groupSyncable.GroupId = groupChannel.GroupId
   482  		groupSyncable.AutoAdd = groupChannel.AutoAdd
   483  		groupSyncable.CreateAt = groupChannel.CreateAt
   484  		groupSyncable.DeleteAt = groupChannel.DeleteAt
   485  		groupSyncable.UpdateAt = groupChannel.UpdateAt
   486  		groupSyncable.Type = syncableType
   487  	default:
   488  		return nil, fmt.Errorf("unable to convert syncableType: %s", syncableType.String())
   489  	}
   490  
   491  	return &groupSyncable, nil
   492  }
   493  
   494  func (s *SqlSupplier) GroupGetAllGroupSyncablesByGroup(ctx context.Context, groupID string, syncableType model.GroupSyncableType, hints ...store.LayeredStoreHint) *store.LayeredStoreSupplierResult {
   495  	result := store.NewSupplierResult()
   496  
   497  	args := map[string]interface{}{"GroupId": groupID}
   498  
   499  	appErrF := func(msg string) *model.AppError {
   500  		return model.NewAppError("SqlGroupStore.GroupGetAllGroupSyncablesByGroup", "store.select_error", nil, msg, http.StatusInternalServerError)
   501  	}
   502  
   503  	groupSyncables := []*model.GroupSyncable{}
   504  
   505  	switch syncableType {
   506  	case model.GroupSyncableTypeTeam:
   507  		sqlQuery := `
   508  			SELECT
   509  				GroupTeams.*, 
   510  				Teams.DisplayName AS TeamDisplayName, 
   511  				Teams.Type AS TeamType
   512  			FROM 
   513  				GroupTeams
   514  				JOIN Teams ON Teams.Id = GroupTeams.TeamId
   515  			WHERE 
   516  				GroupId = :GroupId AND GroupTeams.DeleteAt = 0`
   517  
   518  		results := []*groupTeamJoin{}
   519  		_, err := s.GetMaster().Select(&results, sqlQuery, args)
   520  		if err != nil {
   521  			result.Err = appErrF(err.Error())
   522  			return result
   523  		}
   524  		for _, result := range results {
   525  			groupSyncable := &model.GroupSyncable{
   526  				SyncableId:      result.TeamId,
   527  				GroupId:         result.GroupId,
   528  				AutoAdd:         result.AutoAdd,
   529  				CreateAt:        result.CreateAt,
   530  				DeleteAt:        result.DeleteAt,
   531  				UpdateAt:        result.UpdateAt,
   532  				Type:            syncableType,
   533  				TeamDisplayName: result.TeamDisplayName,
   534  				TeamType:        result.TeamType,
   535  			}
   536  			groupSyncables = append(groupSyncables, groupSyncable)
   537  		}
   538  	case model.GroupSyncableTypeChannel:
   539  		sqlQuery := `
   540  			SELECT
   541  				GroupChannels.*, 
   542  				Channels.DisplayName AS ChannelDisplayName, 
   543  				Teams.DisplayName AS TeamDisplayName,
   544  				Channels.Type As ChannelType,
   545  				Teams.Type As TeamType,
   546  				Teams.Id AS TeamId
   547  			FROM 
   548  				GroupChannels 
   549  				JOIN Channels ON Channels.Id = GroupChannels.ChannelId
   550  				JOIN Teams ON Teams.Id = Channels.TeamId
   551  			WHERE 
   552  				GroupId = :GroupId AND GroupChannels.DeleteAt = 0`
   553  
   554  		results := []*groupChannelJoin{}
   555  		_, err := s.GetMaster().Select(&results, sqlQuery, args)
   556  		if err != nil {
   557  			result.Err = appErrF(err.Error())
   558  			return result
   559  		}
   560  		for _, result := range results {
   561  			groupSyncable := &model.GroupSyncable{
   562  				SyncableId:         result.ChannelId,
   563  				GroupId:            result.GroupId,
   564  				AutoAdd:            result.AutoAdd,
   565  				CreateAt:           result.CreateAt,
   566  				DeleteAt:           result.DeleteAt,
   567  				UpdateAt:           result.UpdateAt,
   568  				Type:               syncableType,
   569  				ChannelDisplayName: result.ChannelDisplayName,
   570  				ChannelType:        result.ChannelType,
   571  				TeamDisplayName:    result.TeamDisplayName,
   572  				TeamType:           result.TeamType,
   573  				TeamID:             result.TeamID,
   574  			}
   575  			groupSyncables = append(groupSyncables, groupSyncable)
   576  		}
   577  	}
   578  
   579  	result.Data = groupSyncables
   580  	return result
   581  }
   582  
   583  func (s *SqlSupplier) GroupUpdateGroupSyncable(ctx context.Context, groupSyncable *model.GroupSyncable, hints ...store.LayeredStoreHint) *store.LayeredStoreSupplierResult {
   584  	result := store.NewSupplierResult()
   585  
   586  	retrievedGroupSyncable, err := s.getGroupSyncable(groupSyncable.GroupId, groupSyncable.SyncableId, groupSyncable.Type)
   587  	if err != nil {
   588  		if err == sql.ErrNoRows {
   589  			result.Err = model.NewAppError("SqlGroupStore.GroupUpdateGroupSyncable", "store.sql_group.no_rows", nil, err.Error(), http.StatusInternalServerError)
   590  			return result
   591  		}
   592  		result.Err = model.NewAppError("SqlGroupStore.GroupUpdateGroupSyncable", "store.select_error", nil, "GroupId="+groupSyncable.GroupId+", SyncableId="+groupSyncable.SyncableId+", SyncableType="+groupSyncable.Type.String()+", "+err.Error(), http.StatusInternalServerError)
   593  		return result
   594  	}
   595  
   596  	if err := groupSyncable.IsValid(); err != nil {
   597  		result.Err = err
   598  		return result
   599  	}
   600  
   601  	// If updating DeleteAt it can only be to 0
   602  	if groupSyncable.DeleteAt != retrievedGroupSyncable.DeleteAt && groupSyncable.DeleteAt != 0 {
   603  		result.Err = model.NewAppError("SqlGroupStore.GroupUpdateGroupSyncable", "model.group.delete_at.app_error", nil, "", http.StatusInternalServerError)
   604  		return result
   605  	}
   606  
   607  	// Reset these properties, don't update them based on input
   608  	groupSyncable.CreateAt = retrievedGroupSyncable.CreateAt
   609  	groupSyncable.UpdateAt = model.GetMillis()
   610  
   611  	switch groupSyncable.Type {
   612  	case model.GroupSyncableTypeTeam:
   613  		_, err = s.GetMaster().Update(groupSyncableToGroupTeam(groupSyncable))
   614  	case model.GroupSyncableTypeChannel:
   615  		_, err = s.GetMaster().Update(groupSyncableToGroupChannel(groupSyncable))
   616  	default:
   617  		model.NewAppError("SqlGroupStore.GroupUpdateGroupSyncable", "model.group_syncable.type.app_error", nil, "group_id="+groupSyncable.GroupId+", syncable_id="+groupSyncable.SyncableId+", "+err.Error(), http.StatusInternalServerError)
   618  		return result
   619  	}
   620  
   621  	if err != nil {
   622  		result.Err = model.NewAppError("SqlGroupStore.GroupUpdateGroupSyncable", "store.update_error", nil, err.Error(), http.StatusInternalServerError)
   623  		return result
   624  	}
   625  
   626  	result.Data = groupSyncable
   627  	return result
   628  }
   629  
   630  func (s *SqlSupplier) GroupDeleteGroupSyncable(ctx context.Context, groupID string, syncableID string, syncableType model.GroupSyncableType, hints ...store.LayeredStoreHint) *store.LayeredStoreSupplierResult {
   631  	result := store.NewSupplierResult()
   632  
   633  	groupSyncable, err := s.getGroupSyncable(groupID, syncableID, syncableType)
   634  	if err != nil {
   635  		if err == sql.ErrNoRows {
   636  			result.Err = model.NewAppError("SqlGroupStore.GroupDeleteGroupSyncable", "store.sql_group.no_rows", nil, "Id="+groupID+", "+err.Error(), http.StatusNotFound)
   637  		} else {
   638  			result.Err = model.NewAppError("SqlGroupStore.GroupDeleteGroupSyncable", "store.select_error", nil, err.Error(), http.StatusInternalServerError)
   639  		}
   640  		return result
   641  	}
   642  
   643  	if groupSyncable.DeleteAt != 0 {
   644  		result.Err = model.NewAppError("SqlGroupStore.GroupDeleteGroupSyncable", "store.sql_group.group_syncable_already_deleted", nil, "group_id="+groupID+"syncable_id="+syncableID, http.StatusBadRequest)
   645  		return result
   646  	}
   647  
   648  	time := model.GetMillis()
   649  	groupSyncable.DeleteAt = time
   650  	groupSyncable.UpdateAt = time
   651  
   652  	switch groupSyncable.Type {
   653  	case model.GroupSyncableTypeTeam:
   654  		_, err = s.GetMaster().Update(groupSyncableToGroupTeam(groupSyncable))
   655  	case model.GroupSyncableTypeChannel:
   656  		_, err = s.GetMaster().Update(groupSyncableToGroupChannel(groupSyncable))
   657  	default:
   658  		model.NewAppError("SqlGroupStore.GroupDeleteGroupSyncable", "model.group_syncable.type.app_error", nil, "group_id="+groupSyncable.GroupId+", syncable_id="+groupSyncable.SyncableId+", "+err.Error(), http.StatusInternalServerError)
   659  		return result
   660  	}
   661  
   662  	if err != nil {
   663  		result.Err = model.NewAppError("SqlGroupStore.GroupDeleteGroupSyncable", "store.update_error", nil, err.Error(), http.StatusInternalServerError)
   664  		return result
   665  	}
   666  
   667  	result.Data = groupSyncable
   668  	return result
   669  }
   670  
   671  // PendingAutoAddTeamMembers returns a slice of UserTeamIDPair that need newly created memberships
   672  // based on the groups configurations.
   673  //
   674  // Typically since will be the last successful group sync time.
   675  func (s *SqlSupplier) PendingAutoAddTeamMembers(ctx context.Context, since int64, hints ...store.LayeredStoreHint) *store.LayeredStoreSupplierResult {
   676  	result := store.NewSupplierResult()
   677  
   678  	sql := `
   679  		SELECT 
   680  			GroupMembers.UserId, GroupTeams.TeamId
   681  		FROM 
   682  			GroupMembers
   683  			JOIN GroupTeams 
   684  			ON GroupTeams.GroupId = GroupMembers.GroupId
   685  			JOIN UserGroups ON UserGroups.Id = GroupMembers.GroupId
   686  			JOIN Teams ON Teams.Id = GroupTeams.TeamId
   687  			LEFT OUTER JOIN TeamMembers 
   688  			ON 
   689  				TeamMembers.TeamId = GroupTeams.TeamId 
   690  				AND TeamMembers.UserId = GroupMembers.UserId
   691  		WHERE 
   692  			TeamMembers.UserId IS NULL
   693  			AND UserGroups.DeleteAt = 0
   694  			AND GroupTeams.DeleteAt = 0
   695  			AND GroupTeams.AutoAdd = true
   696  			AND GroupMembers.DeleteAt = 0
   697  			AND Teams.DeleteAt = 0
   698  			AND (GroupMembers.CreateAt >= :Since
   699  			OR GroupTeams.UpdateAt >= :Since)`
   700  
   701  	var userTeamIDs []*model.UserTeamIDPair
   702  
   703  	_, err := s.GetMaster().Select(&userTeamIDs, sql, map[string]interface{}{"Since": since})
   704  	if err != nil {
   705  		result.Err = model.NewAppError("SqlGroupStore.PendingAutoAddTeamMembers", "store.select_error", nil, err.Error(), http.StatusInternalServerError)
   706  	}
   707  
   708  	result.Data = userTeamIDs
   709  
   710  	return result
   711  }
   712  
   713  // PendingAutoAddChannelMembers returns a slice of UserChannelIDPair that need newly created memberships
   714  // based on the groups configurations.
   715  //
   716  // Typically since will be the last successful group sync time.
   717  func (s *SqlSupplier) PendingAutoAddChannelMembers(ctx context.Context, since int64, hints ...store.LayeredStoreHint) *store.LayeredStoreSupplierResult {
   718  	result := store.NewSupplierResult()
   719  
   720  	sql := `
   721  		SELECT 
   722  			GroupMembers.UserId, GroupChannels.ChannelId
   723  		FROM 
   724  			GroupMembers
   725  			JOIN GroupChannels ON GroupChannels.GroupId = GroupMembers.GroupId
   726  			JOIN UserGroups ON UserGroups.Id = GroupMembers.GroupId
   727  			JOIN Channels ON Channels.Id = GroupChannels.ChannelId
   728  			LEFT OUTER JOIN ChannelMemberHistory 
   729  			ON 
   730  				ChannelMemberHistory.ChannelId = GroupChannels.ChannelId 
   731  				AND ChannelMemberHistory.UserId = GroupMembers.UserId
   732  		WHERE
   733  			ChannelMemberHistory.UserId IS NULL
   734  			AND ChannelMemberHistory.LeaveTime IS NULL
   735  			AND UserGroups.DeleteAt = 0
   736  			AND GroupChannels.DeleteAt = 0
   737  			AND GroupChannels.AutoAdd = true
   738  			AND GroupMembers.DeleteAt = 0
   739  			AND Channels.DeleteAt = 0
   740  			AND (GroupMembers.CreateAt >= :Since
   741  			OR GroupChannels.UpdateAt >= :Since)`
   742  
   743  	var userChannelIDs []*model.UserChannelIDPair
   744  
   745  	_, err := s.GetMaster().Select(&userChannelIDs, sql, map[string]interface{}{"Since": since})
   746  	if err != nil {
   747  		result.Err = model.NewAppError("SqlGroupStore.PendingAutoAddChannelMembers", "store.select_error", nil, "", http.StatusInternalServerError)
   748  	}
   749  
   750  	result.Data = userChannelIDs
   751  
   752  	return result
   753  }
   754  
   755  func groupSyncableToGroupTeam(groupSyncable *model.GroupSyncable) *groupTeam {
   756  	return &groupTeam{
   757  		GroupSyncable: *groupSyncable,
   758  		TeamId:        groupSyncable.SyncableId,
   759  	}
   760  }
   761  
   762  func groupSyncableToGroupChannel(groupSyncable *model.GroupSyncable) *groupChannel {
   763  	return &groupChannel{
   764  		GroupSyncable: *groupSyncable,
   765  		ChannelId:     groupSyncable.SyncableId,
   766  	}
   767  }