Add Options field to RemoteClusters (#25771)
* add Option flag to RemoteClusters * add Options column to RemoteClusters table
Этот коммит содержится в:
@@ -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
|
||||
|
||||
Ссылка в новой задаче
Block a user