github.com/masterhung0112/hk_server/v5@v5.0.0-20220302090640-ec71aef15e1c/store/sqlstore/shared_channel_store.go (about)

     1  // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
     2  // See LICENSE.txt for license information.
     3  
     4  package sqlstore
     5  
     6  import (
     7  	"database/sql"
     8  	"fmt"
     9  
    10  	"github.com/masterhung0112/hk_server/v5/model"
    11  	"github.com/masterhung0112/hk_server/v5/store"
    12  
    13  	sq "github.com/Masterminds/squirrel"
    14  	"github.com/pkg/errors"
    15  )
    16  
    17  const (
    18  	DefaultGetUsersForSyncLimit = 100
    19  )
    20  
    21  type SqlSharedChannelStore struct {
    22  	*SqlStore
    23  }
    24  
    25  func newSqlSharedChannelStore(sqlStore *SqlStore) store.SharedChannelStore {
    26  	s := &SqlSharedChannelStore{
    27  		SqlStore: sqlStore,
    28  	}
    29  
    30  	for _, db := range sqlStore.GetAllConns() {
    31  		tableSharedChannels := db.AddTableWithName(model.SharedChannel{}, "SharedChannels").SetKeys(false, "ChannelId")
    32  		tableSharedChannels.ColMap("ChannelId").SetMaxSize(26)
    33  		tableSharedChannels.ColMap("TeamId").SetMaxSize(26)
    34  		tableSharedChannels.ColMap("CreatorId").SetMaxSize(26)
    35  		tableSharedChannels.ColMap("ShareName").SetMaxSize(64)
    36  		tableSharedChannels.SetUniqueTogether("ShareName", "TeamId")
    37  		tableSharedChannels.ColMap("ShareDisplayName").SetMaxSize(64)
    38  		tableSharedChannels.ColMap("SharePurpose").SetMaxSize(250)
    39  		tableSharedChannels.ColMap("ShareHeader").SetMaxSize(1024)
    40  		tableSharedChannels.ColMap("RemoteId").SetMaxSize(26)
    41  
    42  		tableSharedChannelRemotes := db.AddTableWithName(model.SharedChannelRemote{}, "SharedChannelRemotes").SetKeys(false, "Id", "ChannelId")
    43  		tableSharedChannelRemotes.ColMap("Id").SetMaxSize(26)
    44  		tableSharedChannelRemotes.ColMap("ChannelId").SetMaxSize(26)
    45  		tableSharedChannelRemotes.ColMap("CreatorId").SetMaxSize(26)
    46  		tableSharedChannelRemotes.ColMap("RemoteId").SetMaxSize(26)
    47  		tableSharedChannelRemotes.ColMap("LastPostId").SetMaxSize(26)
    48  		tableSharedChannelRemotes.SetUniqueTogether("ChannelId", "RemoteId")
    49  
    50  		tableSharedChannelUsers := db.AddTableWithName(model.SharedChannelUser{}, "SharedChannelUsers").SetKeys(false, "Id")
    51  		tableSharedChannelUsers.ColMap("Id").SetMaxSize(26)
    52  		tableSharedChannelUsers.ColMap("UserId").SetMaxSize(26)
    53  		tableSharedChannelUsers.ColMap("RemoteId").SetMaxSize(26)
    54  		tableSharedChannelUsers.ColMap("ChannelId").SetMaxSize(26)
    55  		tableSharedChannelUsers.SetUniqueTogether("UserId", "ChannelId", "RemoteId")
    56  
    57  		tableSharedChannelFiles := db.AddTableWithName(model.SharedChannelAttachment{}, "SharedChannelAttachments").SetKeys(false, "Id")
    58  		tableSharedChannelFiles.ColMap("Id").SetMaxSize(26)
    59  		tableSharedChannelFiles.ColMap("FileId").SetMaxSize(26)
    60  		tableSharedChannelFiles.ColMap("RemoteId").SetMaxSize(26)
    61  		tableSharedChannelFiles.SetUniqueTogether("FileId", "RemoteId")
    62  	}
    63  
    64  	return s
    65  }
    66  
    67  func (s SqlSharedChannelStore) createIndexesIfNotExists() {
    68  	s.CreateIndexIfNotExists("idx_sharedchannelusers_remote_id", "SharedChannelUsers", "RemoteId")
    69  }
    70  
    71  // Save inserts a new shared channel record.
    72  func (s SqlSharedChannelStore) Save(sc *model.SharedChannel) (*model.SharedChannel, error) {
    73  	sc.PreSave()
    74  	if err := sc.IsValid(); err != nil {
    75  		return nil, err
    76  	}
    77  
    78  	// make sure the shared channel is associated with a real channel.
    79  	channel, err := s.stores.channel.Get(sc.ChannelId, true)
    80  	if err != nil {
    81  		return nil, fmt.Errorf("invalid channel: %w", err)
    82  	}
    83  
    84  	transaction, err := s.GetMaster().Begin()
    85  	if err != nil {
    86  		return nil, errors.Wrap(err, "begin_transaction")
    87  	}
    88  	defer finalizeTransaction(transaction)
    89  
    90  	if err := transaction.Insert(sc); err != nil {
    91  		return nil, errors.Wrapf(err, "save_shared_channel: ChannelId=%s", sc.ChannelId)
    92  	}
    93  
    94  	// set `Shared` flag in Channels table if needed
    95  	if channel.Shared == nil || !*channel.Shared {
    96  		if err := s.stores.channel.SetShared(channel.Id, true); err != nil {
    97  			return nil, err
    98  		}
    99  	}
   100  
   101  	if err := transaction.Commit(); err != nil {
   102  		return nil, errors.Wrap(err, "commit_transaction")
   103  	}
   104  	return sc, nil
   105  }
   106  
   107  // Get fetches a shared channel by channel_id.
   108  func (s SqlSharedChannelStore) Get(channelId string) (*model.SharedChannel, error) {
   109  	var sc model.SharedChannel
   110  
   111  	query := s.getQueryBuilder().
   112  		Select("*").
   113  		From("SharedChannels").
   114  		Where(sq.Eq{"SharedChannels.ChannelId": channelId})
   115  
   116  	squery, args, err := query.ToSql()
   117  	if err != nil {
   118  		return nil, errors.Wrapf(err, "getsharedchannel_tosql")
   119  	}
   120  
   121  	if err := s.GetReplica().SelectOne(&sc, squery, args...); err != nil {
   122  		if err == sql.ErrNoRows {
   123  			return nil, store.NewErrNotFound("SharedChannel", channelId)
   124  		}
   125  		return nil, errors.Wrapf(err, "failed to find shared channel with ChannelId=%s", channelId)
   126  	}
   127  	return &sc, nil
   128  }
   129  
   130  // HasChannel returns whether a given channelID is a shared channel or not.
   131  func (s SqlSharedChannelStore) HasChannel(channelID string) (bool, error) {
   132  	builder := s.getQueryBuilder().
   133  		Select("1").
   134  		Prefix("SELECT EXISTS (").
   135  		From("SharedChannels").
   136  		Where(sq.Eq{"SharedChannels.ChannelId": channelID}).
   137  		Suffix(")")
   138  
   139  	query, args, err := builder.ToSql()
   140  	if err != nil {
   141  		return false, errors.Wrapf(err, "get_shared_channel_exists_tosql")
   142  	}
   143  
   144  	var exists bool
   145  	if err := s.GetReplica().SelectOne(&exists, query, args...); err != nil {
   146  		return exists, errors.Wrapf(err, "failed to get shared channel for channel_id=%s", channelID)
   147  	}
   148  	return exists, nil
   149  }
   150  
   151  // GetAll fetches a paginated list of shared channels filtered by SharedChannelSearchOpts.
   152  func (s SqlSharedChannelStore) GetAll(offset, limit int, opts model.SharedChannelFilterOpts) ([]*model.SharedChannel, error) {
   153  	if opts.ExcludeHome && opts.ExcludeRemote {
   154  		return nil, errors.New("cannot exclude home and remote shared channels")
   155  	}
   156  
   157  	safeConv := func(offset, limit int) (uint64, uint64, error) {
   158  		if offset < 0 {
   159  			return 0, 0, errors.New("offset must be positive integer")
   160  		}
   161  		if limit < 0 {
   162  			return 0, 0, errors.New("limit must be positive integer")
   163  		}
   164  		return uint64(offset), uint64(limit), nil
   165  	}
   166  
   167  	safeOffset, safeLimit, err := safeConv(offset, limit)
   168  	if err != nil {
   169  		return nil, err
   170  	}
   171  
   172  	query := s.getSharedChannelsQuery(opts, false)
   173  	query = query.OrderBy("sc.ShareDisplayName, sc.ShareName").Limit(safeLimit).Offset(safeOffset)
   174  
   175  	squery, args, err := query.ToSql()
   176  	if err != nil {
   177  		return nil, errors.Wrap(err, "failed to create query")
   178  	}
   179  
   180  	var channels []*model.SharedChannel
   181  	_, err = s.GetReplica().Select(&channels, squery, args...)
   182  	if err != nil {
   183  		return nil, errors.Wrap(err, "failed to get shared channels")
   184  	}
   185  	return channels, nil
   186  }
   187  
   188  // GetAllCount returns the number of shared channels that would be fetched using SharedChannelSearchOpts.
   189  func (s SqlSharedChannelStore) GetAllCount(opts model.SharedChannelFilterOpts) (int64, error) {
   190  	if opts.ExcludeHome && opts.ExcludeRemote {
   191  		return 0, errors.New("cannot exclude home and remote shared channels")
   192  	}
   193  
   194  	query := s.getSharedChannelsQuery(opts, true)
   195  	squery, args, err := query.ToSql()
   196  	if err != nil {
   197  		return 0, errors.Wrap(err, "failed to create query")
   198  	}
   199  
   200  	count, err := s.GetReplica().SelectInt(squery, args...)
   201  	if err != nil {
   202  		return 0, errors.Wrap(err, "failed to count channels")
   203  	}
   204  	return count, nil
   205  }
   206  
   207  func (s SqlSharedChannelStore) getSharedChannelsQuery(opts model.SharedChannelFilterOpts, forCount bool) sq.SelectBuilder {
   208  	var selectStr string
   209  	if forCount {
   210  		selectStr = "count(sc.ChannelId)"
   211  	} else {
   212  		selectStr = "sc.*"
   213  	}
   214  
   215  	query := s.getQueryBuilder().
   216  		Select(selectStr).
   217  		From("SharedChannels AS sc")
   218  
   219  	if opts.TeamId != "" {
   220  		query = query.Where(sq.Eq{"sc.TeamId": opts.TeamId})
   221  	}
   222  
   223  	if opts.CreatorId != "" {
   224  		query = query.Where(sq.Eq{"sc.CreatorId": opts.CreatorId})
   225  	}
   226  
   227  	if opts.ExcludeHome {
   228  		query = query.Where(sq.NotEq{"sc.Home": true})
   229  	}
   230  
   231  	if opts.ExcludeRemote {
   232  		query = query.Where(sq.Eq{"sc.Home": true})
   233  	}
   234  
   235  	return query
   236  }
   237  
   238  // Update updates the shared channel.
   239  func (s SqlSharedChannelStore) Update(sc *model.SharedChannel) (*model.SharedChannel, error) {
   240  	if err := sc.IsValid(); err != nil {
   241  		return nil, err
   242  	}
   243  
   244  	count, err := s.GetMaster().Update(sc)
   245  	if err != nil {
   246  		return nil, errors.Wrapf(err, "failed to update shared channel with channelId=%s", sc.ChannelId)
   247  	}
   248  
   249  	if count != 1 {
   250  		return nil, fmt.Errorf("expected number of shared channels to be updated is 1 but was %d", count)
   251  	}
   252  	return sc, nil
   253  }
   254  
   255  // Delete deletes a single shared channel plus associated SharedChannelRemotes.
   256  // Returns true if shared channel found and deleted, false if not found.
   257  func (s SqlSharedChannelStore) Delete(channelId string) (bool, error) {
   258  	transaction, err := s.GetMaster().Begin()
   259  	if err != nil {
   260  		return false, errors.Wrap(err, "DeleteSharedChannel: begin_transaction")
   261  	}
   262  	defer finalizeTransaction(transaction)
   263  
   264  	squery, args, err := s.getQueryBuilder().
   265  		Delete("SharedChannels").
   266  		Where(sq.Eq{"SharedChannels.ChannelId": channelId}).
   267  		ToSql()
   268  	if err != nil {
   269  		return false, errors.Wrap(err, "delete_shared_channel_tosql")
   270  	}
   271  
   272  	result, err := transaction.Exec(squery, args...)
   273  	if err != nil {
   274  		return false, errors.Wrap(err, "failed to delete SharedChannel")
   275  	}
   276  
   277  	// Also remove remotes from SharedChannelRemotes (if any).
   278  	squery, args, err = s.getQueryBuilder().
   279  		Delete("SharedChannelRemotes").
   280  		Where(sq.Eq{"ChannelId": channelId}).
   281  		ToSql()
   282  	if err != nil {
   283  		return false, errors.Wrap(err, "delete_shared_channel_remotes_tosql")
   284  	}
   285  
   286  	_, err = transaction.Exec(squery, args...)
   287  	if err != nil {
   288  		return false, errors.Wrap(err, "failed to delete SharedChannelRemotes")
   289  	}
   290  
   291  	count, err := result.RowsAffected()
   292  	if err != nil {
   293  		return false, errors.Wrap(err, "failed to determine rows affected")
   294  	}
   295  
   296  	if count > 0 {
   297  		// unset the channel's Shared flag
   298  		if err = s.Channel().SetShared(channelId, false); err != nil {
   299  			return false, errors.Wrap(err, "error unsetting channel share flag")
   300  		}
   301  	}
   302  
   303  	if err = transaction.Commit(); err != nil {
   304  		return false, errors.Wrap(err, "commit_transaction")
   305  	}
   306  
   307  	return count > 0, nil
   308  }
   309  
   310  // SaveRemote inserts a new shared channel remote record.
   311  func (s SqlSharedChannelStore) SaveRemote(remote *model.SharedChannelRemote) (*model.SharedChannelRemote, error) {
   312  	remote.PreSave()
   313  	if err := remote.IsValid(); err != nil {
   314  		return nil, err
   315  	}
   316  
   317  	// make sure the shared channel remote is associated with a real channel.
   318  	if _, err := s.stores.channel.Get(remote.ChannelId, true); err != nil {
   319  		return nil, fmt.Errorf("invalid channel: %w", err)
   320  	}
   321  
   322  	if err := s.GetMaster().Insert(remote); err != nil {
   323  		return nil, errors.Wrapf(err, "save_shared_channel_remote: channel_id=%s, id=%s", remote.ChannelId, remote.Id)
   324  	}
   325  	return remote, nil
   326  }
   327  
   328  // Update updates the shared channel remote.
   329  func (s SqlSharedChannelStore) UpdateRemote(remote *model.SharedChannelRemote) (*model.SharedChannelRemote, error) {
   330  	if err := remote.IsValid(); err != nil {
   331  		return nil, err
   332  	}
   333  
   334  	count, err := s.GetMaster().Update(remote)
   335  	if err != nil {
   336  		return nil, errors.Wrapf(err, "failed to update shared channel remote with remoteId=%s", remote.Id)
   337  	}
   338  
   339  	if count != 1 {
   340  		return nil, fmt.Errorf("expected number of shared channel remotes to be updated is 1 but was %d", count)
   341  	}
   342  	return remote, nil
   343  }
   344  
   345  // GetRemote fetches a shared channel remote by id.
   346  func (s SqlSharedChannelStore) GetRemote(id string) (*model.SharedChannelRemote, error) {
   347  	var remote model.SharedChannelRemote
   348  
   349  	query := s.getQueryBuilder().
   350  		Select("*").
   351  		From("SharedChannelRemotes").
   352  		Where(sq.Eq{"SharedChannelRemotes.Id": id})
   353  
   354  	squery, args, err := query.ToSql()
   355  	if err != nil {
   356  		return nil, errors.Wrapf(err, "get_shared_channel_remote_tosql")
   357  	}
   358  
   359  	if err := s.GetReplica().SelectOne(&remote, squery, args...); err != nil {
   360  		if err == sql.ErrNoRows {
   361  			return nil, store.NewErrNotFound("SharedChannelRemote", id)
   362  		}
   363  		return nil, errors.Wrapf(err, "failed to find shared channel remote with id=%s", id)
   364  	}
   365  	return &remote, nil
   366  }
   367  
   368  // GetRemoteByIds fetches a shared channel remote by channel id and remote cluster id.
   369  func (s SqlSharedChannelStore) GetRemoteByIds(channelId string, remoteId string) (*model.SharedChannelRemote, error) {
   370  	var remote model.SharedChannelRemote
   371  
   372  	query := s.getQueryBuilder().
   373  		Select("*").
   374  		From("SharedChannelRemotes").
   375  		Where(sq.Eq{"SharedChannelRemotes.ChannelId": channelId}).
   376  		Where(sq.Eq{"SharedChannelRemotes.RemoteId": remoteId})
   377  
   378  	squery, args, err := query.ToSql()
   379  	if err != nil {
   380  		return nil, errors.Wrapf(err, "get_shared_channel_remote_by_ids_tosql")
   381  	}
   382  
   383  	if err := s.GetReplica().SelectOne(&remote, squery, args...); err != nil {
   384  		if err == sql.ErrNoRows {
   385  			return nil, store.NewErrNotFound("SharedChannelRemote", fmt.Sprintf("channelId=%s, remoteId=%s", channelId, remoteId))
   386  		}
   387  		return nil, errors.Wrapf(err, "failed to find shared channel remote with channelId=%s, remoteId=%s", channelId, remoteId)
   388  	}
   389  	return &remote, nil
   390  }
   391  
   392  // GetRemotes fetches all shared channel remotes associated with channel_id.
   393  func (s SqlSharedChannelStore) GetRemotes(opts model.SharedChannelRemoteFilterOpts) ([]*model.SharedChannelRemote, error) {
   394  	var remotes []*model.SharedChannelRemote
   395  
   396  	query := s.getQueryBuilder().
   397  		Select("*").
   398  		From("SharedChannelRemotes")
   399  
   400  	if opts.ChannelId != "" {
   401  		query = query.Where(sq.Eq{"ChannelId": opts.ChannelId})
   402  	}
   403  
   404  	if opts.RemoteId != "" {
   405  		query = query.Where(sq.Eq{"RemoteId": opts.RemoteId})
   406  	}
   407  
   408  	if !opts.InclUnconfirmed {
   409  		query = query.Where(sq.Eq{"IsInviteConfirmed": true})
   410  	}
   411  
   412  	squery, args, err := query.ToSql()
   413  	if err != nil {
   414  		return nil, errors.Wrapf(err, "get_shared_channel_remotes_tosql")
   415  	}
   416  
   417  	if _, err := s.GetReplica().Select(&remotes, squery, args...); err != nil {
   418  		if err != sql.ErrNoRows {
   419  			return nil, errors.Wrapf(err, "failed to get shared channel remotes for channel_id=%s; remote_id=%s",
   420  				opts.ChannelId, opts.RemoteId)
   421  		}
   422  	}
   423  	return remotes, nil
   424  }
   425  
   426  // HasRemote returns whether a given remoteId and channelId are present in the shared channel remotes or not.
   427  func (s SqlSharedChannelStore) HasRemote(channelID string, remoteId string) (bool, error) {
   428  	builder := s.getQueryBuilder().
   429  		Select("1").
   430  		Prefix("SELECT EXISTS (").
   431  		From("SharedChannelRemotes").
   432  		Where(sq.Eq{"RemoteId": remoteId}).
   433  		Where(sq.Eq{"ChannelId": channelID}).
   434  		Suffix(")")
   435  
   436  	query, args, err := builder.ToSql()
   437  	if err != nil {
   438  		return false, errors.Wrapf(err, "get_shared_channel_hasremote_tosql")
   439  	}
   440  
   441  	var hasRemote bool
   442  	if err := s.GetReplica().SelectOne(&hasRemote, query, args...); err != nil {
   443  		return hasRemote, errors.Wrapf(err, "failed to get channel remotes for channel_id=%s", channelID)
   444  	}
   445  	return hasRemote, nil
   446  }
   447  
   448  // GetRemoteForUser returns a remote cluster for the given userId only if the user belongs to at least one channel
   449  // shared with the remote.
   450  func (s SqlSharedChannelStore) GetRemoteForUser(remoteId string, userId string) (*model.RemoteCluster, error) {
   451  	builder := s.getQueryBuilder().
   452  		Select("rc.*").
   453  		From("RemoteClusters AS rc").
   454  		Join("SharedChannelRemotes AS scr ON rc.RemoteId = scr.RemoteId").
   455  		Join("ChannelMembers AS cm ON scr.ChannelId = cm.ChannelId").
   456  		Where(sq.Eq{"rc.RemoteId": remoteId}).
   457  		Where(sq.Eq{"cm.UserId": userId})
   458  
   459  	query, args, err := builder.ToSql()
   460  	if err != nil {
   461  		return nil, errors.Wrapf(err, "get_remote_for_user_tosql")
   462  	}
   463  
   464  	var rc model.RemoteCluster
   465  	if err := s.GetReplica().SelectOne(&rc, query, args...); err != nil {
   466  		if err == sql.ErrNoRows {
   467  			return nil, store.NewErrNotFound("RemoteCluster", remoteId)
   468  		}
   469  		return nil, errors.Wrapf(err, "failed to get remote for user_id=%s", userId)
   470  	}
   471  	return &rc, nil
   472  }
   473  
   474  // UpdateRemoteCursor updates the LastPostUpdateAt timestamp and LastPostId for the specified SharedChannelRemote.
   475  func (s SqlSharedChannelStore) UpdateRemoteCursor(id string, cursor model.GetPostsSinceForSyncCursor) error {
   476  	squery, args, err := s.getQueryBuilder().
   477  		Update("SharedChannelRemotes").
   478  		Set("LastPostUpdateAt", cursor.LastPostUpdateAt).
   479  		Set("LastPostId", cursor.LastPostId).
   480  		Where(sq.Eq{"Id": id}).
   481  		ToSql()
   482  	if err != nil {
   483  		return errors.Wrap(err, "update_shared_channel_remote_cursor_tosql")
   484  	}
   485  
   486  	result, err := s.GetMaster().Exec(squery, args...)
   487  	if err != nil {
   488  		return errors.Wrap(err, "failed to update cursor for SharedChannelRemote")
   489  	}
   490  
   491  	count, err := result.RowsAffected()
   492  	if err != nil {
   493  		return errors.Wrap(err, "failed to determine rows affected")
   494  	}
   495  	if count == 0 {
   496  		return fmt.Errorf("id not found: %s", id)
   497  	}
   498  	return nil
   499  }
   500  
   501  // DeleteRemote deletes a single shared channel remote.
   502  // Returns true if remote found and deleted, false if not found.
   503  func (s SqlSharedChannelStore) DeleteRemote(id string) (bool, error) {
   504  	squery, args, err := s.getQueryBuilder().
   505  		Delete("SharedChannelRemotes").
   506  		Where(sq.Eq{"Id": id}).
   507  		ToSql()
   508  	if err != nil {
   509  		return false, errors.Wrap(err, "delete_shared_channel_remote_tosql")
   510  	}
   511  
   512  	result, err := s.GetMaster().Exec(squery, args...)
   513  	if err != nil {
   514  		return false, errors.Wrap(err, "failed to delete SharedChannelRemote")
   515  	}
   516  
   517  	count, err := result.RowsAffected()
   518  	if err != nil {
   519  		return false, errors.Wrap(err, "failed to determine rows affected")
   520  	}
   521  
   522  	return count > 0, nil
   523  }
   524  
   525  // GetRemotesStatus returns the status for each remote invited to the
   526  // specified shared channel.
   527  func (s SqlSharedChannelStore) GetRemotesStatus(channelId string) ([]*model.SharedChannelRemoteStatus, error) {
   528  	var status []*model.SharedChannelRemoteStatus
   529  
   530  	query := s.getQueryBuilder().
   531  		Select("scr.ChannelId, rc.DisplayName, rc.SiteURL, rc.LastPingAt, scr.NextSyncAt, sc.ReadOnly, scr.IsInviteAccepted").
   532  		From("SharedChannelRemotes scr, RemoteClusters rc, SharedChannels sc").
   533  		Where("scr.RemoteId = rc.RemoteId").
   534  		Where("scr.ChannelId = sc.ChannelId").
   535  		Where(sq.Eq{"scr.ChannelId": channelId})
   536  
   537  	squery, args, err := query.ToSql()
   538  	if err != nil {
   539  		return nil, errors.Wrapf(err, "get_shared_channel_remotes_status_tosql")
   540  	}
   541  
   542  	if _, err := s.GetReplica().Select(&status, squery, args...); err != nil {
   543  		if err == sql.ErrNoRows {
   544  			return nil, store.NewErrNotFound("SharedChannelRemoteStatus", channelId)
   545  		}
   546  		return nil, errors.Wrapf(err, "failed to get shared channel remote status for channel_id=%s", channelId)
   547  	}
   548  	return status, nil
   549  }
   550  
   551  // SaveUser inserts a new shared channel user record to the SharedChannelUsers table.
   552  func (s SqlSharedChannelStore) SaveUser(scUser *model.SharedChannelUser) (*model.SharedChannelUser, error) {
   553  	scUser.PreSave()
   554  	if err := scUser.IsValid(); err != nil {
   555  		return nil, err
   556  	}
   557  
   558  	if err := s.GetMaster().Insert(scUser); err != nil {
   559  		return nil, errors.Wrapf(err, "save_shared_channel_user: user_id=%s, remote_id=%s", scUser.UserId, scUser.RemoteId)
   560  	}
   561  	return scUser, nil
   562  }
   563  
   564  // GetSingleUser fetches a shared channel user based on userID, channelID and remoteID.
   565  func (s SqlSharedChannelStore) GetSingleUser(userID string, channelID string, remoteID string) (*model.SharedChannelUser, error) {
   566  	var scu model.SharedChannelUser
   567  
   568  	squery, args, err := s.getQueryBuilder().
   569  		Select("*").
   570  		From("SharedChannelUsers").
   571  		Where(sq.Eq{"SharedChannelUsers.UserId": userID}).
   572  		Where(sq.Eq{"SharedChannelUsers.RemoteId": remoteID}).
   573  		Where(sq.Eq{"SharedChannelUsers.ChannelId": channelID}).
   574  		ToSql()
   575  
   576  	if err != nil {
   577  		return nil, errors.Wrapf(err, "getsharedchannelsingleuser_tosql")
   578  	}
   579  
   580  	if err := s.GetReplica().SelectOne(&scu, squery, args...); err != nil {
   581  		if err == sql.ErrNoRows {
   582  			return nil, store.NewErrNotFound("SharedChannelUser", userID)
   583  		}
   584  		return nil, errors.Wrapf(err, "failed to find shared channel user with UserId=%s, ChannelId=%s, RemoteId=%s", userID, channelID, remoteID)
   585  	}
   586  	return &scu, nil
   587  }
   588  
   589  // GetUsersForUser fetches all shared channel user records based on userID.
   590  func (s SqlSharedChannelStore) GetUsersForUser(userID string) ([]*model.SharedChannelUser, error) {
   591  	squery, args, err := s.getQueryBuilder().
   592  		Select("*").
   593  		From("SharedChannelUsers").
   594  		Where(sq.Eq{"SharedChannelUsers.UserId": userID}).
   595  		ToSql()
   596  
   597  	if err != nil {
   598  		return nil, errors.Wrapf(err, "getsharedchanneluser_tosql")
   599  	}
   600  
   601  	var users []*model.SharedChannelUser
   602  	if _, err := s.GetReplica().Select(&users, squery, args...); err != nil {
   603  		if err == sql.ErrNoRows {
   604  			return make([]*model.SharedChannelUser, 0), nil
   605  		}
   606  		return nil, errors.Wrapf(err, "failed to find shared channel user with UserId=%s", userID)
   607  	}
   608  	return users, nil
   609  }
   610  
   611  // GetUsersForSync fetches all shared channel users that need to be synchronized, meaning their
   612  // `SharedChannelUsers.LastSyncAt` is less than or equal to `User.UpdateAt`.
   613  func (s SqlSharedChannelStore) GetUsersForSync(filter model.GetUsersForSyncFilter) ([]*model.User, error) {
   614  	if filter.Limit <= 0 {
   615  		filter.Limit = DefaultGetUsersForSyncLimit
   616  	}
   617  
   618  	query := s.getQueryBuilder().
   619  		Select("u.*").
   620  		Distinct().
   621  		From("Users AS u").
   622  		Join("SharedChannelUsers AS scu ON u.Id = scu.UserId").
   623  		OrderBy("u.Id").
   624  		Limit(filter.Limit)
   625  
   626  	if filter.CheckProfileImage {
   627  		query = query.Where("scu.LastSyncAt < u.LastPictureUpdate")
   628  	} else {
   629  		query = query.Where("scu.LastSyncAt < u.UpdateAt")
   630  	}
   631  
   632  	if filter.ChannelID != "" {
   633  		query = query.Where(sq.Eq{"scu.ChannelId": filter.ChannelID})
   634  	}
   635  
   636  	sqlQuery, args, err := query.ToSql()
   637  	if err != nil {
   638  		return nil, errors.Wrapf(err, "getsharedchannelusersforsync_tosql")
   639  	}
   640  
   641  	var users []*model.User
   642  	if _, err := s.GetReplica().Select(&users, sqlQuery, args...); err != nil {
   643  		if err == sql.ErrNoRows {
   644  			return make([]*model.User, 0), nil
   645  		}
   646  		return nil, errors.Wrapf(err, "failed to fetch shared channel users with ChannelId=%s",
   647  			filter.ChannelID)
   648  	}
   649  	return users, nil
   650  }
   651  
   652  // UpdateUserLastSyncAt updates the LastSyncAt timestamp for the specified SharedChannelUser.
   653  func (s SqlSharedChannelStore) UpdateUserLastSyncAt(userID string, channelID string, remoteID string) error {
   654  	args := map[string]interface{}{"UserId": userID, "ChannelId": channelID, "RemoteId": remoteID}
   655  
   656  	var query string
   657  	if s.DriverName() == model.DATABASE_DRIVER_POSTGRES {
   658  		query = `
   659  		UPDATE
   660  			SharedChannelUsers AS scu
   661  		SET
   662  			LastSyncAt = GREATEST(Users.UpdateAt, Users.LastPictureUpdate)
   663  		FROM 
   664  			Users
   665  		WHERE
   666  			Users.Id = scu.UserId AND scu.UserId = :UserId AND scu.ChannelId = :ChannelId AND scu.RemoteId = :RemoteId
   667  		`
   668  	} else if s.DriverName() == model.DATABASE_DRIVER_MYSQL {
   669  		query = `
   670  		UPDATE
   671  			SharedChannelUsers AS scu
   672  		INNER JOIN
   673  			Users ON scu.UserId = Users.Id
   674  		SET
   675  			LastSyncAt = GREATEST(Users.UpdateAt, Users.LastPictureUpdate)
   676  		WHERE
   677  			scu.UserId = :UserId AND scu.ChannelId = :ChannelId AND scu.RemoteId = :RemoteId
   678  		`
   679  	} else {
   680  		return errors.New("unsupported DB driver " + s.DriverName())
   681  	}
   682  
   683  	result, err := s.GetMaster().Exec(query, args)
   684  	if err != nil {
   685  		return fmt.Errorf("failed to update LastSyncAt for SharedChannelUser with userId=%s, channelId=%s, remoteId=%s: %w",
   686  			userID, channelID, remoteID, err)
   687  	}
   688  
   689  	count, err := result.RowsAffected()
   690  	if err != nil {
   691  		return errors.Wrap(err, "failed to determine rows affected")
   692  	}
   693  	if count == 0 {
   694  		return fmt.Errorf("SharedChannelUser not found: userId=%s, channelId=%s, remoteId=%s", userID, channelID, remoteID)
   695  	}
   696  	return nil
   697  }
   698  
   699  // SaveAttachment inserts a new shared channel file attachment record to the SharedChannelFiles table.
   700  func (s SqlSharedChannelStore) SaveAttachment(attachment *model.SharedChannelAttachment) (*model.SharedChannelAttachment, error) {
   701  	attachment.PreSave()
   702  	if err := attachment.IsValid(); err != nil {
   703  		return nil, err
   704  	}
   705  
   706  	if err := s.GetMaster().Insert(attachment); err != nil {
   707  		return nil, errors.Wrapf(err, "save_shared_channel_attachment: file_id=%s, remote_id=%s", attachment.FileId, attachment.RemoteId)
   708  	}
   709  	return attachment, nil
   710  }
   711  
   712  // UpsertAttachment inserts a new shared channel file attachment record to the SharedChannelFiles table or updates its
   713  // LastSyncAt.
   714  func (s SqlSharedChannelStore) UpsertAttachment(attachment *model.SharedChannelAttachment) (string, error) {
   715  	attachment.PreSave()
   716  	if err := attachment.IsValid(); err != nil {
   717  		return "", err
   718  	}
   719  
   720  	params := map[string]interface{}{
   721  		"Id":         attachment.Id,
   722  		"FileId":     attachment.FileId,
   723  		"RemoteId":   attachment.RemoteId,
   724  		"CreateAt":   attachment.CreateAt,
   725  		"LastSyncAt": attachment.LastSyncAt,
   726  	}
   727  
   728  	if s.DriverName() == model.DATABASE_DRIVER_MYSQL {
   729  		if _, err := s.GetMaster().Exec(
   730  			`INSERT INTO
   731  				SharedChannelAttachments
   732  				(Id, FileId, RemoteId, CreateAt, LastSyncAt)
   733  			VALUES
   734  				(:Id, :FileId, :RemoteId, :CreateAt, :LastSyncAt)
   735  			ON DUPLICATE KEY UPDATE
   736  				LastSyncAt = :LastSyncAt`, params); err != nil {
   737  			return "", err
   738  		}
   739  	} else if s.DriverName() == model.DATABASE_DRIVER_POSTGRES {
   740  		if _, err := s.GetMaster().Exec(
   741  			`INSERT INTO
   742  				SharedChannelAttachments
   743  				(Id, FileId, RemoteId, CreateAt, LastSyncAt)
   744  			VALUES
   745  				(:Id, :FileId, :RemoteId, :CreateAt, :LastSyncAt)
   746  			ON CONFLICT (Id) 
   747  				DO UPDATE SET LastSyncAt = :LastSyncAt`, params); err != nil {
   748  			return "", err
   749  		}
   750  	}
   751  	return attachment.Id, nil
   752  }
   753  
   754  // GetAttachment fetches a shared channel file attachment record based on file_id and remoteId.
   755  func (s SqlSharedChannelStore) GetAttachment(fileId string, remoteId string) (*model.SharedChannelAttachment, error) {
   756  	var attachment model.SharedChannelAttachment
   757  
   758  	squery, args, err := s.getQueryBuilder().
   759  		Select("*").
   760  		From("SharedChannelAttachments").
   761  		Where(sq.Eq{"SharedChannelAttachments.FileId": fileId}).
   762  		Where(sq.Eq{"SharedChannelAttachments.RemoteId": remoteId}).
   763  		ToSql()
   764  
   765  	if err != nil {
   766  		return nil, errors.Wrapf(err, "getsharedchannelattachment_tosql")
   767  	}
   768  
   769  	if err := s.GetReplica().SelectOne(&attachment, squery, args...); err != nil {
   770  		if err == sql.ErrNoRows {
   771  			return nil, store.NewErrNotFound("SharedChannelAttachment", fileId)
   772  		}
   773  		return nil, errors.Wrapf(err, "failed to find shared channel attachment with FileId=%s, RemoteId=%s", fileId, remoteId)
   774  	}
   775  	return &attachment, nil
   776  }
   777  
   778  // UpdateAttachmentLastSyncAt updates the LastSyncAt timestamp for the specified SharedChannelAttachment.
   779  func (s SqlSharedChannelStore) UpdateAttachmentLastSyncAt(id string, syncTime int64) error {
   780  	squery, args, err := s.getQueryBuilder().
   781  		Update("SharedChannelAttachments").
   782  		Set("LastSyncAt", syncTime).
   783  		Where(sq.Eq{"Id": id}).
   784  		ToSql()
   785  	if err != nil {
   786  		return errors.Wrap(err, "update_shared_channel_attachment_last_sync_at_tosql")
   787  	}
   788  
   789  	result, err := s.GetMaster().Exec(squery, args...)
   790  	if err != nil {
   791  		return errors.Wrap(err, "failed to update LastSycnAt for SharedChannelAttachment")
   792  	}
   793  
   794  	count, err := result.RowsAffected()
   795  	if err != nil {
   796  		return errors.Wrap(err, "failed to determine rows affected")
   797  	}
   798  	if count == 0 {
   799  		return fmt.Errorf("id not found: %s", id)
   800  	}
   801  	return nil
   802  }