Add Options field to RemoteClusters (#25771)

* add Option flag to RemoteClusters

* add Options column to RemoteClusters table
Этот коммит содержится в:
Doug Lauder
2023-12-19 13:01:35 -05:00
коммит произвёл GitHub
родитель f118b4f0ed
Коммит d56dc9d0ce
8 изменённых файлов: 102 добавлений и 15 удалений

Просмотреть файл

@@ -234,6 +234,8 @@ channels/db/migrations/mysql/000117_msteams_shared_channels.down.sql
channels/db/migrations/mysql/000117_msteams_shared_channels.up.sql
channels/db/migrations/mysql/000118_create_index_poststats.down.sql
channels/db/migrations/mysql/000118_create_index_poststats.up.sql
channels/db/migrations/mysql/000119_msteams_shared_channels_opts.down.sql
channels/db/migrations/mysql/000119_msteams_shared_channels_opts.up.sql
channels/db/migrations/postgres/000001_create_teams.down.sql
channels/db/migrations/postgres/000001_create_teams.up.sql
channels/db/migrations/postgres/000002_create_team_members.down.sql
@@ -468,3 +470,5 @@ channels/db/migrations/postgres/000117_msteams_shared_channels.down.sql
channels/db/migrations/postgres/000117_msteams_shared_channels.up.sql
channels/db/migrations/postgres/000118_create_index_poststats.down.sql
channels/db/migrations/postgres/000118_create_index_poststats.up.sql
channels/db/migrations/postgres/000119_msteams_shared_channels_opts.down.sql
channels/db/migrations/postgres/000119_msteams_shared_channels_opts.up.sql

Просмотреть файл

@@ -0,0 +1,15 @@
SET @preparedStatement = (SELECT IF(
EXISTS(
SELECT 1 FROM INFORMATION_SCHEMA.STATISTICS
WHERE table_name = 'RemoteClusters'
AND table_schema = DATABASE()
AND column_name = 'Options'
),
'ALTER TABLE RemoteClusters DROP COLUMN Options;',
'SELECT 1;'
));
PREPARE removeColumnIfExists FROM @preparedStatement;
EXECUTE removeColumnIfExists;
DEALLOCATE PREPARE removeColumnIfExists;

Просмотреть файл

@@ -0,0 +1,15 @@
SET @preparedStatement = (SELECT IF(
NOT EXISTS(
SELECT 1 FROM INFORMATION_SCHEMA.COLUMNS
WHERE table_name = 'RemoteClusters'
AND table_schema = DATABASE()
AND column_name = 'Options'
),
'ALTER TABLE RemoteClusters ADD COLUMN Options smallint NOT NULL DEFAULT 0;',
'SELECT 1;'
));
PREPARE addColumnIfNotExists FROM @preparedStatement;
EXECUTE addColumnIfNotExists;
DEALLOCATE PREPARE addColumnIfNotExists;

Просмотреть файл

@@ -0,0 +1,2 @@
ALTER TABLE RemoteClusters DROP COLUMN IF EXISTS Options;

Просмотреть файл

@@ -0,0 +1,2 @@
ALTER TABLE RemoteClusters ADD COLUMN IF NOT EXISTS Options SMALLINT NOT NULL DEFAULT 0;

Просмотреть файл

@@ -40,6 +40,7 @@ func remoteClusterFields(prefix string) []string {
prefix + "Topics",
prefix + "CreatorId",
prefix + "PluginID",
prefix + "Options",
}
}
@@ -51,10 +52,10 @@ func (s sqlRemoteClusterStore) Save(remoteCluster *model.RemoteCluster) (*model.
query := `INSERT INTO RemoteClusters
(RemoteId, RemoteTeamId, Name, DisplayName, SiteURL, CreateAt,
LastPingAt, Token, RemoteToken, Topics, CreatorId, PluginID)
LastPingAt, Token, RemoteToken, Topics, CreatorId, PluginID, Options)
VALUES
(:RemoteId, :RemoteTeamId, :Name, :DisplayName, :SiteURL, :CreateAt,
:LastPingAt, :Token, :RemoteToken, :Topics, :CreatorId, :PluginID)`
:LastPingAt, :Token, :RemoteToken, :Topics, :CreatorId, :PluginID, :Options)`
if _, err := s.GetMasterX().NamedExec(query, remoteCluster); err != nil {
return nil, errors.Wrap(err, "failed to save RemoteCluster")
@@ -78,7 +79,8 @@ func (s sqlRemoteClusterStore) Update(remoteCluster *model.RemoteCluster) (*mode
DisplayName = :DisplayName,
SiteURL = :SiteURL,
Topics = :Topics,
PluginID = :PluginID
PluginID = :PluginID,
Options = :Options
WHERE RemoteId = :RemoteId AND Name = :Name`
if _, err := s.GetMasterX().NamedExec(query, remoteCluster); err != nil {

Просмотреть файл

@@ -44,6 +44,7 @@ func testRemoteClusterSave(t *testing.T, rctx request.CTX, ss store.Store) {
require.Equal(t, rc.SiteURL, rcSaved.SiteURL)
require.Greater(t, rc.CreateAt, int64(0))
require.Equal(t, rc.LastPingAt, int64(0))
require.Equal(t, rc.Options, model.Bitmask(0))
})
t.Run("Save missing display name", func(t *testing.T) {
@@ -63,6 +64,32 @@ func testRemoteClusterSave(t *testing.T, rctx request.CTX, ss store.Store) {
_, err := ss.RemoteCluster().Save(rc)
require.Error(t, err)
})
t.Run("Save for plugin with options", func(t *testing.T) {
rc := &model.RemoteCluster{
Name: "plugin_remote",
SiteURL: "plugin.example.com",
CreatorId: model.NewId(),
PluginID: testPluginID,
Options: model.BitflagOptionAutoShareDMs,
}
rcSaved, err := ss.RemoteCluster().Save(rc)
require.NoError(t, err)
require.Equal(t, testPluginID, rcSaved.PluginID)
require.Equal(t, model.BitflagOptionAutoShareDMs, rcSaved.Options)
require.True(t, rcSaved.IsOptionFlagSet(model.BitflagOptionAutoShareDMs))
rc.Name = "plugin_remote_2"
rc.SiteURL = "plugin2.example.com"
rc.UnsetOptionFlag(model.BitflagOptionAutoShareDMs)
rcSaved, err = ss.RemoteCluster().Save(rc)
require.NoError(t, err)
require.Equal(t, testPluginID, rcSaved.PluginID)
require.Equal(t, model.Bitmask(0), rcSaved.Options)
require.False(t, rcSaved.IsOptionFlagSet(model.BitflagOptionAutoShareDMs))
})
}
func testRemoteClusterDelete(t *testing.T, rctx request.CTX, ss store.Store) {
@@ -95,6 +122,7 @@ func testRemoteClusterGet(t *testing.T, rctx request.CTX, ss store.Store) {
CreatorId: model.NewId(),
PluginID: testPluginID,
}
rc.SetOptionFlag(model.BitflagOptionAutoShareDMs)
rcSaved, err := ss.RemoteCluster().Save(rc)
require.NoError(t, err)
@@ -102,6 +130,7 @@ func testRemoteClusterGet(t *testing.T, rctx request.CTX, ss store.Store) {
require.NoError(t, err)
require.Equal(t, rcSaved.RemoteId, rcGet.RemoteId)
require.Equal(t, testPluginID, rcGet.PluginID)
require.True(t, rcGet.IsOptionFlagSet(model.BitflagOptionAutoShareDMs))
})
t.Run("Get not found", func(t *testing.T) {

Просмотреть файл

@@ -21,25 +21,30 @@ const (
RemoteOfflineAfterMillis = 1000 * 60 * 5 // 5 minutes
RemoteNameMinLength = 1
RemoteNameMaxLength = 64
BitflagOptionAutoShareDMs Bitmask = 1 << iota
)
var (
validRemoteNameChars = regexp.MustCompile(`^[a-zA-Z0-9\.\-\_]+$`)
)
type Bitmask uint32
type RemoteCluster struct {
RemoteId string `json:"remote_id"`
RemoteTeamId string `json:"remote_team_id"`
Name string `json:"name"`
DisplayName string `json:"display_name"`
SiteURL string `json:"site_url"`
CreateAt int64 `json:"create_at"`
LastPingAt int64 `json:"last_ping_at"`
Token string `json:"token"`
RemoteToken string `json:"remote_token"`
Topics string `json:"topics"`
CreatorId string `json:"creator_id"`
PluginID string `json:"plugin_id"` // non-empty when sync message are to be delivered via plugin API
RemoteId string `json:"remote_id"`
RemoteTeamId string `json:"remote_team_id"`
Name string `json:"name"`
DisplayName string `json:"display_name"`
SiteURL string `json:"site_url"`
CreateAt int64 `json:"create_at"`
LastPingAt int64 `json:"last_ping_at"`
Token string `json:"token"`
RemoteToken string `json:"remote_token"`
Topics string `json:"topics"`
CreatorId string `json:"creator_id"`
PluginID string `json:"plugin_id"` // non-empty when sync message are to be delivered via plugin API
Options Bitmask `json:"options"` // bit-flag set of options
}
func (rc *RemoteCluster) Auditable() map[string]interface{} {
@@ -53,6 +58,7 @@ func (rc *RemoteCluster) Auditable() map[string]interface{} {
"last_ping_at": rc.LastPingAt,
"creator_id": rc.CreatorId,
"plugin_id": rc.PluginID,
"options": rc.Options,
}
}
@@ -98,6 +104,18 @@ func (rc *RemoteCluster) IsValid() *AppError {
return nil
}
func (rc *RemoteCluster) IsOptionFlagSet(flag Bitmask) bool {
return rc.Options&flag != 0
}
func (rc *RemoteCluster) SetOptionFlag(flag Bitmask) {
rc.Options |= flag
}
func (rc *RemoteCluster) UnsetOptionFlag(flag Bitmask) {
rc.Options &= ^flag
}
func IsValidRemoteName(s string) bool {
if len(s) < RemoteNameMinLength || len(s) > RemoteNameMaxLength {
return false