github.com/jfrerich/mattermost-server@v5.8.0-rc2+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.CanLeave = groupTeam.CanLeave
   474  		groupSyncable.AutoAdd = groupTeam.AutoAdd
   475  		groupSyncable.CreateAt = groupTeam.CreateAt
   476  		groupSyncable.DeleteAt = groupTeam.DeleteAt
   477  		groupSyncable.UpdateAt = groupTeam.UpdateAt
   478  		groupSyncable.Type = syncableType
   479  	case model.GroupSyncableTypeChannel:
   480  		groupChannel := result.(*groupChannel)
   481  		groupSyncable.SyncableId = groupChannel.ChannelId
   482  		groupSyncable.GroupId = groupChannel.GroupId
   483  		groupSyncable.CanLeave = groupChannel.CanLeave
   484  		groupSyncable.AutoAdd = groupChannel.AutoAdd
   485  		groupSyncable.CreateAt = groupChannel.CreateAt
   486  		groupSyncable.DeleteAt = groupChannel.DeleteAt
   487  		groupSyncable.UpdateAt = groupChannel.UpdateAt
   488  		groupSyncable.Type = syncableType
   489  	default:
   490  		return nil, fmt.Errorf("unable to convert syncableType: %s", syncableType.String())
   491  	}
   492  
   493  	return &groupSyncable, nil
   494  }
   495  
   496  func (s *SqlSupplier) GroupGetAllGroupSyncablesByGroup(ctx context.Context, groupID string, syncableType model.GroupSyncableType, hints ...store.LayeredStoreHint) *store.LayeredStoreSupplierResult {
   497  	result := store.NewSupplierResult()
   498  
   499  	args := map[string]interface{}{"GroupId": groupID}
   500  
   501  	appErrF := func(msg string) *model.AppError {
   502  		return model.NewAppError("SqlGroupStore.GroupGetAllGroupSyncablesByGroup", "store.select_error", nil, msg, http.StatusInternalServerError)
   503  	}
   504  
   505  	groupSyncables := []*model.GroupSyncable{}
   506  
   507  	switch syncableType {
   508  	case model.GroupSyncableTypeTeam:
   509  		sqlQuery := `
   510  			SELECT
   511  				GroupTeams.*, 
   512  				Teams.DisplayName AS TeamDisplayName, 
   513  				Teams.Type AS TeamType
   514  			FROM 
   515  				GroupTeams
   516  				JOIN Teams ON Teams.Id = GroupTeams.TeamId
   517  			WHERE 
   518  				GroupId = :GroupId AND GroupTeams.DeleteAt = 0`
   519  
   520  		results := []*groupTeamJoin{}
   521  		_, err := s.GetMaster().Select(&results, sqlQuery, args)
   522  		if err != nil {
   523  			result.Err = appErrF(err.Error())
   524  			return result
   525  		}
   526  		for _, result := range results {
   527  			groupSyncable := &model.GroupSyncable{
   528  				SyncableId:      result.TeamId,
   529  				GroupId:         result.GroupId,
   530  				CanLeave:        result.CanLeave,
   531  				AutoAdd:         result.AutoAdd,
   532  				CreateAt:        result.CreateAt,
   533  				DeleteAt:        result.DeleteAt,
   534  				UpdateAt:        result.UpdateAt,
   535  				Type:            syncableType,
   536  				TeamDisplayName: result.TeamDisplayName,
   537  				TeamType:        result.TeamType,
   538  			}
   539  			groupSyncables = append(groupSyncables, groupSyncable)
   540  		}
   541  	case model.GroupSyncableTypeChannel:
   542  		sqlQuery := `
   543  			SELECT
   544  				GroupChannels.*, 
   545  				Channels.DisplayName AS ChannelDisplayName, 
   546  				Teams.DisplayName AS TeamDisplayName,
   547  				Channels.Type As ChannelType,
   548  				Teams.Type As TeamType,
   549  				Teams.Id AS TeamId
   550  			FROM 
   551  				GroupChannels 
   552  				JOIN Channels ON Channels.Id = GroupChannels.ChannelId
   553  				JOIN Teams ON Teams.Id = Channels.TeamId
   554  			WHERE 
   555  				GroupId = :GroupId AND GroupChannels.DeleteAt = 0`
   556  
   557  		results := []*groupChannelJoin{}
   558  		_, err := s.GetMaster().Select(&results, sqlQuery, args)
   559  		if err != nil {
   560  			result.Err = appErrF(err.Error())
   561  			return result
   562  		}
   563  		for _, result := range results {
   564  			groupSyncable := &model.GroupSyncable{
   565  				SyncableId:         result.ChannelId,
   566  				GroupId:            result.GroupId,
   567  				CanLeave:           result.CanLeave,
   568  				AutoAdd:            result.AutoAdd,
   569  				CreateAt:           result.CreateAt,
   570  				DeleteAt:           result.DeleteAt,
   571  				UpdateAt:           result.UpdateAt,
   572  				Type:               syncableType,
   573  				ChannelDisplayName: result.ChannelDisplayName,
   574  				ChannelType:        result.ChannelType,
   575  				TeamDisplayName:    result.TeamDisplayName,
   576  				TeamType:           result.TeamType,
   577  				TeamID:             result.TeamID,
   578  			}
   579  			groupSyncables = append(groupSyncables, groupSyncable)
   580  		}
   581  	}
   582  
   583  	result.Data = groupSyncables
   584  	return result
   585  }
   586  
   587  func (s *SqlSupplier) GroupUpdateGroupSyncable(ctx context.Context, groupSyncable *model.GroupSyncable, hints ...store.LayeredStoreHint) *store.LayeredStoreSupplierResult {
   588  	result := store.NewSupplierResult()
   589  
   590  	retrievedGroupSyncable, err := s.getGroupSyncable(groupSyncable.GroupId, groupSyncable.SyncableId, groupSyncable.Type)
   591  	if err != nil {
   592  		if err == sql.ErrNoRows {
   593  			result.Err = model.NewAppError("SqlGroupStore.GroupUpdateGroupSyncable", "store.sql_group.no_rows", nil, err.Error(), http.StatusInternalServerError)
   594  			return result
   595  		}
   596  		result.Err = model.NewAppError("SqlGroupStore.GroupUpdateGroupSyncable", "store.select_error", nil, "GroupId="+groupSyncable.GroupId+", SyncableId="+groupSyncable.SyncableId+", SyncableType="+groupSyncable.Type.String()+", "+err.Error(), http.StatusInternalServerError)
   597  		return result
   598  	}
   599  
   600  	if err := groupSyncable.IsValid(); err != nil {
   601  		result.Err = err
   602  		return result
   603  	}
   604  
   605  	// If updating DeleteAt it can only be to 0
   606  	if groupSyncable.DeleteAt != retrievedGroupSyncable.DeleteAt && groupSyncable.DeleteAt != 0 {
   607  		result.Err = model.NewAppError("SqlGroupStore.GroupUpdateGroupSyncable", "model.group.delete_at.app_error", nil, "", http.StatusInternalServerError)
   608  		return result
   609  	}
   610  
   611  	// Reset these properties, don't update them based on input
   612  	groupSyncable.CreateAt = retrievedGroupSyncable.CreateAt
   613  	groupSyncable.UpdateAt = model.GetMillis()
   614  
   615  	switch groupSyncable.Type {
   616  	case model.GroupSyncableTypeTeam:
   617  		_, err = s.GetMaster().Update(groupSyncableToGroupTeam(groupSyncable))
   618  	case model.GroupSyncableTypeChannel:
   619  		_, err = s.GetMaster().Update(groupSyncableToGroupChannel(groupSyncable))
   620  	default:
   621  		model.NewAppError("SqlGroupStore.GroupUpdateGroupSyncable", "model.group_syncable.type.app_error", nil, "group_id="+groupSyncable.GroupId+", syncable_id="+groupSyncable.SyncableId+", "+err.Error(), http.StatusInternalServerError)
   622  		return result
   623  	}
   624  
   625  	if err != nil {
   626  		result.Err = model.NewAppError("SqlGroupStore.GroupUpdateGroupSyncable", "store.update_error", nil, err.Error(), http.StatusInternalServerError)
   627  		return result
   628  	}
   629  
   630  	result.Data = groupSyncable
   631  	return result
   632  }
   633  
   634  func (s *SqlSupplier) GroupDeleteGroupSyncable(ctx context.Context, groupID string, syncableID string, syncableType model.GroupSyncableType, hints ...store.LayeredStoreHint) *store.LayeredStoreSupplierResult {
   635  	result := store.NewSupplierResult()
   636  
   637  	groupSyncable, err := s.getGroupSyncable(groupID, syncableID, syncableType)
   638  	if err != nil {
   639  		if err == sql.ErrNoRows {
   640  			result.Err = model.NewAppError("SqlGroupStore.GroupDeleteGroupSyncable", "store.sql_group.no_rows", nil, "Id="+groupID+", "+err.Error(), http.StatusNotFound)
   641  		} else {
   642  			result.Err = model.NewAppError("SqlGroupStore.GroupDeleteGroupSyncable", "store.select_error", nil, err.Error(), http.StatusInternalServerError)
   643  		}
   644  		return result
   645  	}
   646  
   647  	if groupSyncable.DeleteAt != 0 {
   648  		result.Err = model.NewAppError("SqlGroupStore.GroupDeleteGroupSyncable", "store.sql_group.group_syncable_already_deleted", nil, "group_id="+groupID+"syncable_id="+syncableID, http.StatusBadRequest)
   649  		return result
   650  	}
   651  
   652  	time := model.GetMillis()
   653  	groupSyncable.DeleteAt = time
   654  	groupSyncable.UpdateAt = time
   655  
   656  	switch groupSyncable.Type {
   657  	case model.GroupSyncableTypeTeam:
   658  		_, err = s.GetMaster().Update(groupSyncableToGroupTeam(groupSyncable))
   659  	case model.GroupSyncableTypeChannel:
   660  		_, err = s.GetMaster().Update(groupSyncableToGroupChannel(groupSyncable))
   661  	default:
   662  		model.NewAppError("SqlGroupStore.GroupDeleteGroupSyncable", "model.group_syncable.type.app_error", nil, "group_id="+groupSyncable.GroupId+", syncable_id="+groupSyncable.SyncableId+", "+err.Error(), http.StatusInternalServerError)
   663  		return result
   664  	}
   665  
   666  	if err != nil {
   667  		result.Err = model.NewAppError("SqlGroupStore.GroupDeleteGroupSyncable", "store.update_error", nil, err.Error(), http.StatusInternalServerError)
   668  		return result
   669  	}
   670  
   671  	result.Data = groupSyncable
   672  	return result
   673  }
   674  
   675  // PendingAutoAddTeamMembers returns a slice of UserTeamIDPair that need newly created memberships
   676  // based on the groups configurations.
   677  //
   678  // Typically since will be the last successful group sync time.
   679  func (s *SqlSupplier) PendingAutoAddTeamMembers(ctx context.Context, since int64, hints ...store.LayeredStoreHint) *store.LayeredStoreSupplierResult {
   680  	result := store.NewSupplierResult()
   681  
   682  	sql := `
   683  		SELECT 
   684  			GroupMembers.UserId, GroupTeams.TeamId
   685  		FROM 
   686  			GroupMembers
   687  			JOIN GroupTeams 
   688  			ON GroupTeams.GroupId = GroupMembers.GroupId
   689  			JOIN UserGroups ON UserGroups.Id = GroupMembers.GroupId
   690  			JOIN Teams ON Teams.Id = GroupTeams.TeamId
   691  			LEFT OUTER JOIN TeamMembers 
   692  			ON 
   693  				TeamMembers.TeamId = GroupTeams.TeamId 
   694  				AND TeamMembers.UserId = GroupMembers.UserId
   695  		WHERE 
   696  			TeamMembers.UserId IS NULL
   697  			AND UserGroups.DeleteAt = 0
   698  			AND GroupTeams.DeleteAt = 0
   699  			AND GroupTeams.AutoAdd = true
   700  			AND GroupMembers.DeleteAt = 0
   701  			AND Teams.DeleteAt = 0
   702  			AND (GroupMembers.CreateAt >= :Since
   703  			OR GroupTeams.UpdateAt >= :Since)`
   704  
   705  	var userTeamIDs []*model.UserTeamIDPair
   706  
   707  	_, err := s.GetMaster().Select(&userTeamIDs, sql, map[string]interface{}{"Since": since})
   708  	if err != nil {
   709  		result.Err = model.NewAppError("SqlGroupStore.PendingAutoAddTeamMembers", "store.select_error", nil, err.Error(), http.StatusInternalServerError)
   710  	}
   711  
   712  	result.Data = userTeamIDs
   713  
   714  	return result
   715  }
   716  
   717  // PendingAutoAddChannelMembers returns a slice of UserChannelIDPair that need newly created memberships
   718  // based on the groups configurations.
   719  //
   720  // Typically since will be the last successful group sync time.
   721  func (s *SqlSupplier) PendingAutoAddChannelMembers(ctx context.Context, since int64, hints ...store.LayeredStoreHint) *store.LayeredStoreSupplierResult {
   722  	result := store.NewSupplierResult()
   723  
   724  	sql := `
   725  		SELECT 
   726  			GroupMembers.UserId, GroupChannels.ChannelId
   727  		FROM 
   728  			GroupMembers
   729  			JOIN GroupChannels ON GroupChannels.GroupId = GroupMembers.GroupId
   730  			JOIN UserGroups ON UserGroups.Id = GroupMembers.GroupId
   731  			JOIN Channels ON Channels.Id = GroupChannels.ChannelId
   732  			LEFT OUTER JOIN ChannelMemberHistory 
   733  			ON 
   734  				ChannelMemberHistory.ChannelId = GroupChannels.ChannelId 
   735  				AND ChannelMemberHistory.UserId = GroupMembers.UserId
   736  		WHERE
   737  			ChannelMemberHistory.UserId IS NULL
   738  			AND ChannelMemberHistory.LeaveTime IS NULL
   739  			AND UserGroups.DeleteAt = 0
   740  			AND GroupChannels.DeleteAt = 0
   741  			AND GroupChannels.AutoAdd = true
   742  			AND GroupMembers.DeleteAt = 0
   743  			AND Channels.DeleteAt = 0
   744  			AND (GroupMembers.CreateAt >= :Since
   745  			OR GroupChannels.UpdateAt >= :Since)`
   746  
   747  	var userChannelIDs []*model.UserChannelIDPair
   748  
   749  	_, err := s.GetMaster().Select(&userChannelIDs, sql, map[string]interface{}{"Since": since})
   750  	if err != nil {
   751  		result.Err = model.NewAppError("SqlGroupStore.PendingAutoAddChannelMembers", "store.select_error", nil, "", http.StatusInternalServerError)
   752  	}
   753  
   754  	result.Data = userChannelIDs
   755  
   756  	return result
   757  }
   758  
   759  func groupSyncableToGroupTeam(groupSyncable *model.GroupSyncable) *groupTeam {
   760  	return &groupTeam{
   761  		GroupSyncable: *groupSyncable,
   762  		TeamId:        groupSyncable.SyncableId,
   763  	}
   764  }
   765  
   766  func groupSyncableToGroupChannel(groupSyncable *model.GroupSyncable) *groupChannel {
   767  	return &groupChannel{
   768  		GroupSyncable: *groupSyncable,
   769  		ChannelId:     groupSyncable.SyncableId,
   770  	}
   771  }