Allows invites to be sent to offline remotes (#28176)
* Allows invites to be sent to offline remotes Invites sent to remotes marked as offline will be stored as pending, and when the remote comes back online, it will process the invites as part of the synchronization process. * Update condition name for excluding confirmed invites
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
d879927876
Коммит
f41d54b336
@@ -52,6 +52,30 @@ func (scs *Service) SendChannelInvite(channel *model.Channel, userId string, rc
|
||||
return err
|
||||
}
|
||||
|
||||
// if the remote is not currently online, we store the invite to
|
||||
// send it when the connection is restored
|
||||
if !rc.IsOnline() {
|
||||
if len(options) > 0 {
|
||||
// pending invites with options are currently not supported
|
||||
scs.sendEphemeralPost(channel.Id, userId, fmt.Sprintf("Error sending channel invite for %s: %s", rc.DisplayName, model.ErrOfflineRemote))
|
||||
return model.ErrOfflineRemote
|
||||
}
|
||||
|
||||
scr := &model.SharedChannelRemote{
|
||||
ChannelId: sc.ChannelId,
|
||||
CreatorId: userId,
|
||||
RemoteId: rc.RemoteId,
|
||||
IsInviteAccepted: true,
|
||||
IsInviteConfirmed: false,
|
||||
}
|
||||
if _, err = scs.server.GetStore().SharedChannel().SaveRemote(scr); err != nil {
|
||||
scs.sendEphemeralPost(channel.Id, userId, fmt.Sprintf("Error saving channel invite for %s: %v", rc.DisplayName, err))
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
invite := channelInviteMsg{
|
||||
ChannelId: channel.Id,
|
||||
ReadOnly: sc.ReadOnly,
|
||||
@@ -89,18 +113,20 @@ func (scs *Service) SendChannelInvite(channel *model.Channel, userId string, rc
|
||||
|
||||
curTime := model.GetMillis()
|
||||
if existingScr != nil {
|
||||
if existingScr.DeleteAt == 0 {
|
||||
if existingScr.DeleteAt == 0 && existingScr.IsInviteConfirmed {
|
||||
// the shared channel remote exists and is not
|
||||
// deleted, nothing to do here
|
||||
return
|
||||
}
|
||||
|
||||
// the shared channel remote was deleted in the past, so
|
||||
// with the new invite we restore it
|
||||
// the shared channel remote was deleted in the past or
|
||||
// pending confirmation, so with the new invite we restore
|
||||
// it
|
||||
existingScr.DeleteAt = 0
|
||||
existingScr.UpdateAt = curTime
|
||||
existingScr.LastPostCreateAt = curTime
|
||||
existingScr.LastPostUpdateAt = curTime
|
||||
existingScr.IsInviteConfirmed = true
|
||||
if _, sErr := scs.server.GetStore().SharedChannel().UpdateRemote(existingScr); sErr != nil {
|
||||
scs.sendEphemeralPost(channel.Id, userId, fmt.Sprintf("Error confirming channel invite for %s: %v", rc.DisplayName, sErr))
|
||||
return
|
||||
|
||||
@@ -244,6 +244,7 @@ func (scs *Service) makeChannelReadOnly(channel *model.Channel) *model.AppError
|
||||
func (scs *Service) onConnectionStateChange(rc *model.RemoteCluster, online bool) {
|
||||
if online {
|
||||
// when a previously offline remote comes back online force a sync.
|
||||
scs.SendPendingInvitesForRemote(rc)
|
||||
scs.ForceSyncForRemote(rc)
|
||||
}
|
||||
|
||||
|
||||
@@ -150,6 +150,61 @@ func (scs *Service) NotifyUserStatusChanged(status *model.Status) {
|
||||
}
|
||||
}
|
||||
|
||||
func (scs *Service) SendPendingInvitesForRemote(rc *model.RemoteCluster) {
|
||||
if rcs := scs.server.GetRemoteClusterService(); rcs == nil {
|
||||
return
|
||||
}
|
||||
|
||||
scs.server.Log().Log(mlog.LvlSharedChannelServiceDebug, "Processing pending invites for remote after reconnection",
|
||||
mlog.String("remote", rc.DisplayName),
|
||||
mlog.String("remoteId", rc.RemoteId),
|
||||
)
|
||||
|
||||
opts := model.SharedChannelRemoteFilterOpts{
|
||||
RemoteId: rc.RemoteId,
|
||||
ExcludeConfirmed: true,
|
||||
}
|
||||
scrs, err := scs.server.GetStore().SharedChannel().GetRemotes(0, 999999, opts)
|
||||
if err != nil {
|
||||
scs.server.Log().Log(mlog.LvlSharedChannelServiceError, "Failed to fetch shared channel remotes for pending invites",
|
||||
mlog.String("remote", rc.DisplayName),
|
||||
mlog.String("remoteId", rc.RemoteId),
|
||||
mlog.Err(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
for _, scr := range scrs {
|
||||
channel, err := scs.server.GetStore().Channel().Get(scr.ChannelId, true)
|
||||
if err != nil {
|
||||
scs.server.Log().Log(mlog.LvlSharedChannelServiceError, "Failed to fetch channel for pending invite",
|
||||
mlog.String("remote_id", scr.RemoteId),
|
||||
mlog.String("channel_id", scr.ChannelId),
|
||||
mlog.String("sharedchannelremote_id", scr.Id),
|
||||
mlog.Err(err),
|
||||
)
|
||||
continue
|
||||
}
|
||||
|
||||
if err := scs.SendChannelInvite(channel, scr.CreatorId, rc); err != nil {
|
||||
scs.server.Log().Log(mlog.LvlSharedChannelServiceError, "Failed to send pending invite",
|
||||
mlog.String("remote_id", scr.RemoteId),
|
||||
mlog.String("channel_id", scr.ChannelId),
|
||||
mlog.String("sharedchannelremote_id", scr.Id),
|
||||
mlog.Err(err),
|
||||
)
|
||||
continue
|
||||
}
|
||||
|
||||
scs.server.Log().Log(mlog.LvlSharedChannelServiceDebug, "Pending invite sent",
|
||||
mlog.String("remote", rc.DisplayName),
|
||||
mlog.String("remoteId", rc.RemoteId),
|
||||
mlog.String("channel_id", scr.ChannelId),
|
||||
mlog.String("sharedchannelremote_id", scr.Id),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// ForceSyncForRemote causes all channels shared with the remote to be synchronized.
|
||||
func (scs *Service) ForceSyncForRemote(rc *model.RemoteCluster) {
|
||||
if rcs := scs.server.GetRemoteClusterService(); rcs == nil {
|
||||
@@ -327,9 +382,10 @@ func (scs *Service) processTask(task syncTask) error {
|
||||
remotesMap[r.RemoteId] = r
|
||||
}
|
||||
|
||||
// add all remotes that have the autoinvited option.
|
||||
// add all confirmed remotes that have the autoinvited option.
|
||||
filter = model.RemoteClusterQueryFilter{
|
||||
RequireOptions: model.BitflagOptionAutoInvited,
|
||||
OnlyConfirmed: true,
|
||||
}
|
||||
remotesAutoInvited, err := scs.server.GetStore().RemoteCluster().GetAll(0, 999999, filter)
|
||||
if err != nil {
|
||||
|
||||
Ссылка в новой задаче
Block a user