Reject mysql for enterprise advanced (#31164)
* reject MySQL with the enterprise advanced license If a user attempts to set an Enterprise Advanced License while configured with MySQL, reject the license. This SKU is not compatible with MYSQL. * fix trial typo * suppress trial banner if MySQL * Update server/channels/app/platform/license_test.go Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * fix types * suppress mysql from show start trial modal * Skip MySQL-incompatible tests for access control and channel banner features Skip the following tests when running with MySQL database: - Access control policy tests (create, get, delete, check/test expressions, search, assign/unassign, get channels) - Channel banner tests in TestPatchChannel and TestCanEditChannelBanner These features are not supported on MySQL and the tests would fail. Tests will continue to run normally on PostgreSQL. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * Skip TestSearchChannelsForAccessControlPolicy subtest for MySQL Add MySQL skip logic to the "SearchChannelsForAccessControlPolicy with regular user" subtest as this access control feature is not supported on MySQL. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * reject trial license requests for MySQL * return false on sku + mysql match, even if logger is nil * Fix MySQL trial license tests to skip appropriately based on database driver 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: Claude <noreply@anthropic.com>
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
f2bb82bc01
Коммит
70a42ffd5f
@@ -22,6 +22,10 @@ func TestCreateAccessControlPolicy(t *testing.T) {
|
|||||||
os.Unsetenv("MM_FEATUREFLAGS_ATTRIBUTEBASEDACCESSCONTROL")
|
os.Unsetenv("MM_FEATUREFLAGS_ATTRIBUTEBASEDACCESSCONTROL")
|
||||||
})
|
})
|
||||||
|
|
||||||
|
if *mainHelper.GetSQLSettings().DriverName == model.DatabaseDriverMysql {
|
||||||
|
t.Skip("Access control tests are not supported on MySQL")
|
||||||
|
}
|
||||||
|
|
||||||
samplePolicy := &model.AccessControlPolicy{
|
samplePolicy := &model.AccessControlPolicy{
|
||||||
Type: model.AccessControlPolicyTypeChannel,
|
Type: model.AccessControlPolicyTypeChannel,
|
||||||
Version: model.AccessControlPolicyVersionV0_1,
|
Version: model.AccessControlPolicyVersionV0_1,
|
||||||
@@ -89,6 +93,10 @@ func TestGetAccessControlPolicy(t *testing.T) {
|
|||||||
os.Unsetenv("MM_FEATUREFLAGS_ATTRIBUTEBASEDACCESSCONTROL")
|
os.Unsetenv("MM_FEATUREFLAGS_ATTRIBUTEBASEDACCESSCONTROL")
|
||||||
})
|
})
|
||||||
|
|
||||||
|
if *mainHelper.GetSQLSettings().DriverName == model.DatabaseDriverMysql {
|
||||||
|
t.Skip("Access control tests are not supported on MySQL")
|
||||||
|
}
|
||||||
|
|
||||||
samplePolicy := &model.AccessControlPolicy{
|
samplePolicy := &model.AccessControlPolicy{
|
||||||
ID: model.NewId(),
|
ID: model.NewId(),
|
||||||
Type: model.AccessControlPolicyTypeChannel,
|
Type: model.AccessControlPolicyTypeChannel,
|
||||||
@@ -152,6 +160,10 @@ func TestDeleteAccessControlPolicy(t *testing.T) {
|
|||||||
os.Unsetenv("MM_FEATUREFLAGS_ATTRIBUTEBASEDACCESSCONTROL")
|
os.Unsetenv("MM_FEATUREFLAGS_ATTRIBUTEBASEDACCESSCONTROL")
|
||||||
})
|
})
|
||||||
|
|
||||||
|
if *mainHelper.GetSQLSettings().DriverName == model.DatabaseDriverMysql {
|
||||||
|
t.Skip("Access control tests are not supported on MySQL")
|
||||||
|
}
|
||||||
|
|
||||||
samplePolicyID := model.NewId()
|
samplePolicyID := model.NewId()
|
||||||
|
|
||||||
t.Run("DeleteAccessControlPolicy without license", func(t *testing.T) {
|
t.Run("DeleteAccessControlPolicy without license", func(t *testing.T) {
|
||||||
@@ -202,6 +214,10 @@ func TestCheckExpression(t *testing.T) {
|
|||||||
os.Unsetenv("MM_FEATUREFLAGS_ATTRIBUTEBASEDACCESSCONTROL")
|
os.Unsetenv("MM_FEATUREFLAGS_ATTRIBUTEBASEDACCESSCONTROL")
|
||||||
})
|
})
|
||||||
|
|
||||||
|
if *mainHelper.GetSQLSettings().DriverName == model.DatabaseDriverMysql {
|
||||||
|
t.Skip("Access control tests are not supported on MySQL")
|
||||||
|
}
|
||||||
|
|
||||||
t.Run("CheckExpression without license", func(t *testing.T) {
|
t.Run("CheckExpression without license", func(t *testing.T) {
|
||||||
_, resp, err := th.SystemAdminClient.CheckExpression(context.Background(), "true")
|
_, resp, err := th.SystemAdminClient.CheckExpression(context.Background(), "true")
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
@@ -275,6 +291,10 @@ func TestTestExpression(t *testing.T) {
|
|||||||
os.Unsetenv("MM_FEATUREFLAGS_ATTRIBUTEBASEDACCESSCONTROL")
|
os.Unsetenv("MM_FEATUREFLAGS_ATTRIBUTEBASEDACCESSCONTROL")
|
||||||
})
|
})
|
||||||
|
|
||||||
|
if *mainHelper.GetSQLSettings().DriverName == model.DatabaseDriverMysql {
|
||||||
|
t.Skip("Access control tests are not supported on MySQL")
|
||||||
|
}
|
||||||
|
|
||||||
t.Run("TestExpression without license", func(t *testing.T) {
|
t.Run("TestExpression without license", func(t *testing.T) {
|
||||||
_, resp, err := th.SystemAdminClient.TestExpression(context.Background(), model.QueryExpressionParams{})
|
_, resp, err := th.SystemAdminClient.TestExpression(context.Background(), model.QueryExpressionParams{})
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
@@ -327,6 +347,10 @@ func TestSearchAccessControlPolicies(t *testing.T) {
|
|||||||
os.Unsetenv("MM_FEATUREFLAGS_ATTRIBUTEBASEDACCESSCONTROL")
|
os.Unsetenv("MM_FEATUREFLAGS_ATTRIBUTEBASEDACCESSCONTROL")
|
||||||
})
|
})
|
||||||
|
|
||||||
|
if *mainHelper.GetSQLSettings().DriverName == model.DatabaseDriverMysql {
|
||||||
|
t.Skip("Access control tests are not supported on MySQL")
|
||||||
|
}
|
||||||
|
|
||||||
t.Run("SearchAccessControlPolicies without license", func(t *testing.T) {
|
t.Run("SearchAccessControlPolicies without license", func(t *testing.T) {
|
||||||
_, resp, err := th.SystemAdminClient.SearchAccessControlPolicies(context.Background(), model.AccessControlPolicySearch{})
|
_, resp, err := th.SystemAdminClient.SearchAccessControlPolicies(context.Background(), model.AccessControlPolicySearch{})
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
@@ -381,6 +405,10 @@ func TestAssignAccessPolicy(t *testing.T) {
|
|||||||
os.Unsetenv("MM_FEATUREFLAGS_ATTRIBUTEBASEDACCESSCONTROL")
|
os.Unsetenv("MM_FEATUREFLAGS_ATTRIBUTEBASEDACCESSCONTROL")
|
||||||
})
|
})
|
||||||
|
|
||||||
|
if *mainHelper.GetSQLSettings().DriverName == model.DatabaseDriverMysql {
|
||||||
|
t.Skip("Access control tests are not supported on MySQL")
|
||||||
|
}
|
||||||
|
|
||||||
samplePolicy := &model.AccessControlPolicy{
|
samplePolicy := &model.AccessControlPolicy{
|
||||||
ID: model.NewId(),
|
ID: model.NewId(),
|
||||||
Type: model.AccessControlPolicyTypeParent,
|
Type: model.AccessControlPolicyTypeParent,
|
||||||
@@ -448,6 +476,10 @@ func TestUnassignAccessPolicy(t *testing.T) {
|
|||||||
os.Unsetenv("MM_FEATUREFLAGS_ATTRIBUTEBASEDACCESSCONTROL")
|
os.Unsetenv("MM_FEATUREFLAGS_ATTRIBUTEBASEDACCESSCONTROL")
|
||||||
})
|
})
|
||||||
|
|
||||||
|
if *mainHelper.GetSQLSettings().DriverName == model.DatabaseDriverMysql {
|
||||||
|
t.Skip("Access control tests are not supported on MySQL")
|
||||||
|
}
|
||||||
|
|
||||||
samplePolicy := &model.AccessControlPolicy{
|
samplePolicy := &model.AccessControlPolicy{
|
||||||
ID: model.NewId(),
|
ID: model.NewId(),
|
||||||
Type: model.AccessControlPolicyTypeParent,
|
Type: model.AccessControlPolicyTypeParent,
|
||||||
@@ -519,6 +551,10 @@ func TestGetChannelsForAccessControlPolicy(t *testing.T) {
|
|||||||
os.Unsetenv("MM_FEATUREFLAGS_ATTRIBUTEBASEDACCESSCONTROL")
|
os.Unsetenv("MM_FEATUREFLAGS_ATTRIBUTEBASEDACCESSCONTROL")
|
||||||
})
|
})
|
||||||
|
|
||||||
|
if *mainHelper.GetSQLSettings().DriverName == model.DatabaseDriverMysql {
|
||||||
|
t.Skip("Access control tests are not supported on MySQL")
|
||||||
|
}
|
||||||
|
|
||||||
samplePolicy := &model.AccessControlPolicy{
|
samplePolicy := &model.AccessControlPolicy{
|
||||||
ID: model.NewId(),
|
ID: model.NewId(),
|
||||||
Type: model.AccessControlPolicyTypeParent,
|
Type: model.AccessControlPolicyTypeParent,
|
||||||
@@ -596,6 +632,10 @@ func TestSearchChannelsForAccessControlPolicy(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
t.Run("SearchChannelsForAccessControlPolicy with regular user", func(t *testing.T) {
|
t.Run("SearchChannelsForAccessControlPolicy with regular user", func(t *testing.T) {
|
||||||
|
if *mainHelper.GetSQLSettings().DriverName == model.DatabaseDriverMysql {
|
||||||
|
t.Skip("Access control tests are not supported on MySQL")
|
||||||
|
}
|
||||||
|
|
||||||
ok := th.App.Srv().SetLicense(model.NewTestLicenseSKU(model.LicenseShortSkuEnterpriseAdvanced))
|
ok := th.App.Srv().SetLicense(model.NewTestLicenseSKU(model.LicenseShortSkuEnterpriseAdvanced))
|
||||||
require.True(t, ok, "SetLicense should return true")
|
require.True(t, ok, "SetLicense should return true")
|
||||||
|
|
||||||
|
|||||||
@@ -810,6 +810,10 @@ func TestPatchChannel(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
t.Run("Should be able to configure channel banner on a channel", func(t *testing.T) {
|
t.Run("Should be able to configure channel banner on a channel", func(t *testing.T) {
|
||||||
|
if *mainHelper.GetSQLSettings().DriverName == model.DatabaseDriverMysql {
|
||||||
|
t.Skip("Channel banner tests are not supported on MySQL")
|
||||||
|
}
|
||||||
|
|
||||||
client.Logout(context.Background())
|
client.Logout(context.Background())
|
||||||
th.LoginBasic()
|
th.LoginBasic()
|
||||||
th.App.Srv().SetLicense(model.NewTestLicenseSKU(model.LicenseShortSkuEnterpriseAdvanced))
|
th.App.Srv().SetLicense(model.NewTestLicenseSKU(model.LicenseShortSkuEnterpriseAdvanced))
|
||||||
@@ -866,6 +870,10 @@ func TestPatchChannel(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
t.Run("Should be able to configure channel banner as a team admin", func(t *testing.T) {
|
t.Run("Should be able to configure channel banner as a team admin", func(t *testing.T) {
|
||||||
|
if *mainHelper.GetSQLSettings().DriverName == model.DatabaseDriverMysql {
|
||||||
|
t.Skip("Channel banner tests are not supported on MySQL")
|
||||||
|
}
|
||||||
|
|
||||||
client.Logout(context.Background())
|
client.Logout(context.Background())
|
||||||
th.LoginTeamAdmin()
|
th.LoginTeamAdmin()
|
||||||
th.App.Srv().SetLicense(model.NewTestLicenseSKU(model.LicenseShortSkuEnterpriseAdvanced))
|
th.App.Srv().SetLicense(model.NewTestLicenseSKU(model.LicenseShortSkuEnterpriseAdvanced))
|
||||||
@@ -891,6 +899,10 @@ func TestPatchChannel(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
t.Run("Cannot enable channel banner without configuring it", func(t *testing.T) {
|
t.Run("Cannot enable channel banner without configuring it", func(t *testing.T) {
|
||||||
|
if *mainHelper.GetSQLSettings().DriverName == model.DatabaseDriverMysql {
|
||||||
|
t.Skip("Channel banner tests are not supported on MySQL")
|
||||||
|
}
|
||||||
|
|
||||||
client.Logout(context.Background())
|
client.Logout(context.Background())
|
||||||
th.LoginBasic()
|
th.LoginBasic()
|
||||||
th.App.Srv().SetLicense(model.NewTestLicenseSKU(model.LicenseShortSkuEnterpriseAdvanced))
|
th.App.Srv().SetLicense(model.NewTestLicenseSKU(model.LicenseShortSkuEnterpriseAdvanced))
|
||||||
@@ -1010,6 +1022,10 @@ func TestCanEditChannelBanner(t *testing.T) {
|
|||||||
th := Setup(t).InitBasic()
|
th := Setup(t).InitBasic()
|
||||||
defer th.TearDown()
|
defer th.TearDown()
|
||||||
|
|
||||||
|
if *mainHelper.GetSQLSettings().DriverName == model.DatabaseDriverMysql {
|
||||||
|
t.Skip("Channel banner tests are not supported on MySQL")
|
||||||
|
}
|
||||||
|
|
||||||
t.Run("when license is nil", func(t *testing.T) {
|
t.Run("when license is nil", func(t *testing.T) {
|
||||||
channel := &model.Channel{
|
channel := &model.Channel{
|
||||||
Type: model.ChannelTypeOpen,
|
Type: model.ChannelTypeOpen,
|
||||||
|
|||||||
@@ -186,6 +186,12 @@ func requestTrialLicense(c *Context, w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MySQL is not supported for trial licenses
|
||||||
|
if c.App.Config().SqlSettings.DriverName != nil && *c.App.Config().SqlSettings.DriverName == model.DatabaseDriverMysql {
|
||||||
|
c.Err = model.NewAppError("requestTrialLicense", "api.license.request-trial.mysql.app_error", nil, "mysql is not supported for trial licenses", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if c.App.Srv().Platform().LicenseManager() == nil {
|
if c.App.Srv().Platform().LicenseManager() == nil {
|
||||||
c.Err = model.NewAppError("requestTrialLicense", "api.license.upgrade_needed.app_error", nil, "", http.StatusForbidden)
|
c.Err = model.NewAppError("requestTrialLicense", "api.license.upgrade_needed.app_error", nil, "", http.StatusForbidden)
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -258,7 +258,27 @@ func TestRequestTrialLicenseWithExtraFields(t *testing.T) {
|
|||||||
CheckForbiddenStatus(t, resp)
|
CheckForbiddenStatus(t, resp)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.Run("mysql database not supported", func(t *testing.T) {
|
||||||
|
// Skip this test unless running with MySQL driver
|
||||||
|
if *th.App.Config().SqlSettings.DriverName != model.DatabaseDriverMysql {
|
||||||
|
t.Skip("Skipping test - only runs with MySQL driver")
|
||||||
|
}
|
||||||
|
|
||||||
|
licenseManagerMock := &mocks.LicenseInterface{}
|
||||||
|
licenseManagerMock.On("CanStartTrial").Return(true, nil).Once()
|
||||||
|
th.App.Srv().Platform().SetLicenseManager(licenseManagerMock)
|
||||||
|
|
||||||
|
resp, err := th.SystemAdminClient.RequestTrialLicenseWithExtraFields(context.Background(), validTrialRequest)
|
||||||
|
CheckErrorID(t, err, "api.license.request-trial.mysql.app_error")
|
||||||
|
CheckBadRequestStatus(t, resp)
|
||||||
|
})
|
||||||
|
|
||||||
t.Run("trial license user count less than current users", func(t *testing.T) {
|
t.Run("trial license user count less than current users", func(t *testing.T) {
|
||||||
|
// Skip this test when MySQL is configured as it hits the MySQL check first
|
||||||
|
if *th.App.Config().SqlSettings.DriverName == model.DatabaseDriverMysql {
|
||||||
|
t.Skip("Skipping test - MySQL does not support trial licenses")
|
||||||
|
}
|
||||||
|
|
||||||
license := model.NewTestLicense()
|
license := model.NewTestLicense()
|
||||||
license.Features.Users = model.NewPointer(nUsers)
|
license.Features.Users = model.NewPointer(nUsers)
|
||||||
licenseJSON, jsonErr := json.Marshal(license)
|
licenseJSON, jsonErr := json.Marshal(license)
|
||||||
@@ -295,6 +315,11 @@ func TestRequestTrialLicenseWithExtraFields(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
t.Run("returns status 451 when it receives status 451", func(t *testing.T) {
|
t.Run("returns status 451 when it receives status 451", func(t *testing.T) {
|
||||||
|
// Skip this test when MySQL is configured as it hits the MySQL check first
|
||||||
|
if *th.App.Config().SqlSettings.DriverName == model.DatabaseDriverMysql {
|
||||||
|
t.Skip("Skipping test - MySQL does not support trial licenses")
|
||||||
|
}
|
||||||
|
|
||||||
license := model.NewTestLicense()
|
license := model.NewTestLicense()
|
||||||
license.Features.Users = model.NewPointer(nUsers)
|
license.Features.Users = model.NewPointer(nUsers)
|
||||||
licenseJSON, jsonErr := json.Marshal(license)
|
licenseJSON, jsonErr := json.Marshal(license)
|
||||||
@@ -325,6 +350,11 @@ func TestRequestTrialLicenseWithExtraFields(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
t.Run("returns status 400 if request is a mix of legacy and new fields", func(t *testing.T) {
|
t.Run("returns status 400 if request is a mix of legacy and new fields", func(t *testing.T) {
|
||||||
|
// Skip this test when MySQL is configured as it hits the MySQL check first
|
||||||
|
if *th.App.Config().SqlSettings.DriverName == model.DatabaseDriverMysql {
|
||||||
|
t.Skip("Skipping test - MySQL does not support trial licenses")
|
||||||
|
}
|
||||||
|
|
||||||
validTrialRequest.CompanyCountry = ""
|
validTrialRequest.CompanyCountry = ""
|
||||||
validTrialRequest.Users = 100
|
validTrialRequest.Users = 100
|
||||||
defer func() { validTrialRequest.CompanyCountry = "US" }()
|
defer func() { validTrialRequest.CompanyCountry = "US" }()
|
||||||
@@ -365,6 +395,11 @@ func TestRequestTrialLicenseWithExtraFields(t *testing.T) {
|
|||||||
|
|
||||||
th.App.Srv().Platform().SetLicenseManager(nil)
|
th.App.Srv().Platform().SetLicenseManager(nil)
|
||||||
t.Run("trial license should fail if LicenseManager is nil", func(t *testing.T) {
|
t.Run("trial license should fail if LicenseManager is nil", func(t *testing.T) {
|
||||||
|
// Skip this test when MySQL is configured as it hits the MySQL check first
|
||||||
|
if *th.App.Config().SqlSettings.DriverName == model.DatabaseDriverMysql {
|
||||||
|
t.Skip("Skipping test - MySQL does not support trial licenses")
|
||||||
|
}
|
||||||
|
|
||||||
resp, err := th.SystemAdminClient.RequestTrialLicenseWithExtraFields(context.Background(), validTrialRequest)
|
resp, err := th.SystemAdminClient.RequestTrialLicenseWithExtraFields(context.Background(), validTrialRequest)
|
||||||
CheckErrorID(t, err, "api.license.upgrade_needed.app_error")
|
CheckErrorID(t, err, "api.license.upgrade_needed.app_error")
|
||||||
CheckForbiddenStatus(t, resp)
|
CheckForbiddenStatus(t, resp)
|
||||||
@@ -387,7 +422,27 @@ func TestRequestTrialLicense(t *testing.T) {
|
|||||||
CheckForbiddenStatus(t, resp)
|
CheckForbiddenStatus(t, resp)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.Run("mysql database not supported", func(t *testing.T) {
|
||||||
|
// Skip this test unless running with MySQL driver
|
||||||
|
if *th.App.Config().SqlSettings.DriverName != model.DatabaseDriverMysql {
|
||||||
|
t.Skip("Skipping test - only runs with MySQL driver")
|
||||||
|
}
|
||||||
|
|
||||||
|
licenseManagerMock := &mocks.LicenseInterface{}
|
||||||
|
licenseManagerMock.On("CanStartTrial").Return(true, nil).Once()
|
||||||
|
th.App.Srv().Platform().SetLicenseManager(licenseManagerMock)
|
||||||
|
|
||||||
|
resp, err := th.SystemAdminClient.RequestTrialLicense(context.Background(), 1000)
|
||||||
|
CheckErrorID(t, err, "api.license.request-trial.mysql.app_error")
|
||||||
|
CheckBadRequestStatus(t, resp)
|
||||||
|
})
|
||||||
|
|
||||||
t.Run("trial license invalid JSON", func(t *testing.T) {
|
t.Run("trial license invalid JSON", func(t *testing.T) {
|
||||||
|
// Skip this test when MySQL is configured as it hits the MySQL check first
|
||||||
|
if *th.App.Config().SqlSettings.DriverName == model.DatabaseDriverMysql {
|
||||||
|
t.Skip("Skipping test - MySQL does not support trial licenses")
|
||||||
|
}
|
||||||
|
|
||||||
// the JSON is invalid because it is missing a closing brace
|
// the JSON is invalid because it is missing a closing brace
|
||||||
|
|
||||||
licenseManagerMock := &mocks.LicenseInterface{}
|
licenseManagerMock := &mocks.LicenseInterface{}
|
||||||
@@ -400,6 +455,11 @@ func TestRequestTrialLicense(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
t.Run("trial license user count less than current users", func(t *testing.T) {
|
t.Run("trial license user count less than current users", func(t *testing.T) {
|
||||||
|
// Skip this test when MySQL is configured as it hits the MySQL check first
|
||||||
|
if *th.App.Config().SqlSettings.DriverName == model.DatabaseDriverMysql {
|
||||||
|
t.Skip("Skipping test - MySQL does not support trial licenses")
|
||||||
|
}
|
||||||
|
|
||||||
nUsers := 1
|
nUsers := 1
|
||||||
license := model.NewTestLicense()
|
license := model.NewTestLicense()
|
||||||
license.Features.Users = model.NewPointer(nUsers)
|
license.Features.Users = model.NewPointer(nUsers)
|
||||||
@@ -435,6 +495,11 @@ func TestRequestTrialLicense(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
t.Run("returns status 451 when it receives status 451", func(t *testing.T) {
|
t.Run("returns status 451 when it receives status 451", func(t *testing.T) {
|
||||||
|
// Skip this test when MySQL is configured as it hits the MySQL check first
|
||||||
|
if *th.App.Config().SqlSettings.DriverName == model.DatabaseDriverMysql {
|
||||||
|
t.Skip("Skipping test - MySQL does not support trial licenses")
|
||||||
|
}
|
||||||
|
|
||||||
nUsers := 1
|
nUsers := 1
|
||||||
license := model.NewTestLicense()
|
license := model.NewTestLicense()
|
||||||
license.Features.Users = model.NewPointer(nUsers)
|
license.Features.Users = model.NewPointer(nUsers)
|
||||||
@@ -467,6 +532,11 @@ func TestRequestTrialLicense(t *testing.T) {
|
|||||||
|
|
||||||
th.App.Srv().Platform().SetLicenseManager(nil)
|
th.App.Srv().Platform().SetLicenseManager(nil)
|
||||||
t.Run("trial license should fail if LicenseManager is nil", func(t *testing.T) {
|
t.Run("trial license should fail if LicenseManager is nil", func(t *testing.T) {
|
||||||
|
// Skip this test when MySQL is configured as it hits the MySQL check first
|
||||||
|
if *th.App.Config().SqlSettings.DriverName == model.DatabaseDriverMysql {
|
||||||
|
t.Skip("Skipping test - MySQL does not support trial licenses")
|
||||||
|
}
|
||||||
|
|
||||||
resp, err := th.SystemAdminClient.RequestTrialLicense(context.Background(), 1)
|
resp, err := th.SystemAdminClient.RequestTrialLicense(context.Background(), 1)
|
||||||
CheckErrorID(t, err, "api.license.upgrade_needed.app_error")
|
CheckErrorID(t, err, "api.license.upgrade_needed.app_error")
|
||||||
CheckForbiddenStatus(t, resp)
|
CheckForbiddenStatus(t, resp)
|
||||||
|
|||||||
@@ -134,6 +134,10 @@ func (ps *PlatformService) SaveLicense(licenseBytes []byte) (*model.License, *mo
|
|||||||
return nil, model.NewAppError("addLicense", "api.license.add_license.invalid.app_error", nil, "", http.StatusBadRequest).Wrap(errors.New("license.Features.Users is nil"))
|
return nil, model.NewAppError("addLicense", "api.license.add_license.invalid.app_error", nil, "", http.StatusBadRequest).Wrap(errors.New("license.Features.Users is nil"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if license.SkuShortName == model.LicenseShortSkuEnterpriseAdvanced && *ps.Config().SqlSettings.DriverName == model.DatabaseDriverMysql {
|
||||||
|
return nil, model.NewAppError("addLicense", "api.license.add_license.mysql.app_error", nil, "", http.StatusBadRequest).Wrap(errors.New("mysql is not supported for this license"))
|
||||||
|
}
|
||||||
|
|
||||||
uniqueUserCount, err := ps.Store.User().Count(model.UserCountOptions{})
|
uniqueUserCount, err := ps.Store.User().Count(model.UserCountOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, model.NewAppError("addLicense", "api.license.add_license.invalid_count.app_error", nil, "", http.StatusBadRequest).Wrap(err)
|
return nil, model.NewAppError("addLicense", "api.license.add_license.invalid_count.app_error", nil, "", http.StatusBadRequest).Wrap(err)
|
||||||
@@ -225,6 +229,13 @@ func (ps *PlatformService) SaveLicense(licenseBytes []byte) (*model.License, *mo
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (ps *PlatformService) SetLicense(license *model.License) bool {
|
func (ps *PlatformService) SetLicense(license *model.License) bool {
|
||||||
|
if license != nil && license.SkuShortName == model.LicenseShortSkuEnterpriseAdvanced && *ps.Config().SqlSettings.DriverName == model.DatabaseDriverMysql {
|
||||||
|
if ps.logger != nil {
|
||||||
|
ps.logger.Error("MySQL is not supported for this license", mlog.String("sku_short_name", license.SkuShortName))
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
oldLicense := ps.licenseValue.Load()
|
oldLicense := ps.licenseValue.Load()
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
|
|||||||
@@ -4,12 +4,17 @@
|
|||||||
package platform
|
package platform
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
"github.com/mattermost/mattermost/server/public/model"
|
"github.com/mattermost/mattermost/server/public/model"
|
||||||
|
"github.com/mattermost/mattermost/server/public/plugin/plugintest/mock"
|
||||||
|
"github.com/mattermost/mattermost/server/v8/channels/utils"
|
||||||
|
mocks2 "github.com/mattermost/mattermost/server/v8/channels/utils/mocks"
|
||||||
|
"github.com/mattermost/mattermost/server/v8/channels/utils/testutils"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestLoadLicense(t *testing.T) {
|
func TestLoadLicense(t *testing.T) {
|
||||||
@@ -30,6 +35,45 @@ func TestSaveLicense(t *testing.T) {
|
|||||||
require.NotNil(t, err, "shouldn't have saved license")
|
require.NotNil(t, err, "shouldn't have saved license")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSaveEnterpriseAdvancedLicense(t *testing.T) {
|
||||||
|
th := Setup(t)
|
||||||
|
defer th.TearDown()
|
||||||
|
|
||||||
|
defer testutils.ResetLicenseValidator()
|
||||||
|
mockLicenseValidator := mocks2.LicenseValidatorIface{}
|
||||||
|
|
||||||
|
license := &model.License{
|
||||||
|
Id: model.NewId(),
|
||||||
|
Features: &model.Features{
|
||||||
|
Users: model.NewPointer(100),
|
||||||
|
},
|
||||||
|
Customer: &model.Customer{
|
||||||
|
Name: "TestName",
|
||||||
|
Email: "test@example.com",
|
||||||
|
},
|
||||||
|
SkuName: "SKU NAME",
|
||||||
|
SkuShortName: model.LicenseShortSkuEnterpriseAdvanced,
|
||||||
|
StartsAt: model.GetMillis() - 1000,
|
||||||
|
ExpiresAt: model.GetMillis() + 100000,
|
||||||
|
}
|
||||||
|
|
||||||
|
mockLicenseValidator.On("LicenseFromBytes", mock.Anything).Return(license, nil).Once()
|
||||||
|
licenseBytes, err := json.Marshal(license)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
mockLicenseValidator.On("ValidateLicense", mock.Anything).Return(string(licenseBytes), nil)
|
||||||
|
utils.LicenseValidator = &mockLicenseValidator
|
||||||
|
|
||||||
|
_, appErr := th.Service.SaveLicense(licenseBytes)
|
||||||
|
|
||||||
|
if *th.Service.Config().SqlSettings.DriverName == model.DatabaseDriverMysql {
|
||||||
|
require.NotNil(t, appErr, "shouldn't have saved license")
|
||||||
|
require.Equal(t, "addLicense: api.license.add_license.mysql.app_error, mysql is not supported for this license", appErr.Error())
|
||||||
|
} else {
|
||||||
|
require.Nil(t, appErr, "should have saved license")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestRemoveLicense(t *testing.T) {
|
func TestRemoveLicense(t *testing.T) {
|
||||||
th := Setup(t)
|
th := Setup(t)
|
||||||
defer th.TearDown()
|
defer th.TearDown()
|
||||||
|
|||||||
@@ -2316,6 +2316,10 @@
|
|||||||
"id": "api.license.add_license.invalid_count.app_error",
|
"id": "api.license.add_license.invalid_count.app_error",
|
||||||
"translation": "Unable to count total unique users."
|
"translation": "Unable to count total unique users."
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"id": "api.license.add_license.mysql.app_error",
|
||||||
|
"translation": "This license does not support MySQL."
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"id": "api.license.add_license.no_file.app_error",
|
"id": "api.license.add_license.no_file.app_error",
|
||||||
"translation": "No file under 'license' in request."
|
"translation": "No file under 'license' in request."
|
||||||
@@ -2368,6 +2372,10 @@
|
|||||||
"id": "api.license.request-trial.can-start-trial.not-allowed",
|
"id": "api.license.request-trial.can-start-trial.not-allowed",
|
||||||
"translation": "Failed to apply new trial license as your workspace has already applied a trial license. If you would like to extend your trial period please [contact our sales team](https://mattermost.com/contact-us/)."
|
"translation": "Failed to apply new trial license as your workspace has already applied a trial license. If you would like to extend your trial period please [contact our sales team](https://mattermost.com/contact-us/)."
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"id": "api.license.request-trial.mysql.app_error",
|
||||||
|
"translation": "Trial licenses are not supported for MySQL databases. Please use PostgreSQL to access trial features."
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"id": "api.license.request_trial_license.app_error",
|
"id": "api.license.request_trial_license.app_error",
|
||||||
"translation": "Unable to get a trial license, please try again or contact with support@mattermost.com."
|
"translation": "Unable to get a trial license, please try again or contact with support@mattermost.com."
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ function mapStateToProps(state: GlobalState) {
|
|||||||
totalUsers: selectFilteredUserStats(state)?.total_users_count || 0,
|
totalUsers: selectFilteredUserStats(state)?.total_users_count || 0,
|
||||||
upgradedFromTE: config.UpgradedFromTE === 'true',
|
upgradedFromTE: config.UpgradedFromTE === 'true',
|
||||||
prevTrialLicense: state.entities.admin.prevTrialLicense,
|
prevTrialLicense: state.entities.admin.prevTrialLicense,
|
||||||
|
isMySql: config.SQLDriverName === 'mysql',
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ describe('components/admin_console/license_settings/LicenseSettings', () => {
|
|||||||
upgradedFromTE: false,
|
upgradedFromTE: false,
|
||||||
enterpriseReady: true,
|
enterpriseReady: true,
|
||||||
totalUsers: 10,
|
totalUsers: 10,
|
||||||
|
isMySql: false,
|
||||||
actions: {
|
actions: {
|
||||||
getLicenseConfig: jest.fn(),
|
getLicenseConfig: jest.fn(),
|
||||||
uploadLicense: jest.fn(),
|
uploadLicense: jest.fn(),
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ type Props = {
|
|||||||
totalUsers: number;
|
totalUsers: number;
|
||||||
isDisabled: boolean;
|
isDisabled: boolean;
|
||||||
prevTrialLicense: ClientLicense;
|
prevTrialLicense: ClientLicense;
|
||||||
|
isMySql: boolean;
|
||||||
actions: {
|
actions: {
|
||||||
getLicenseConfig: () => void;
|
getLicenseConfig: () => void;
|
||||||
uploadLicense: (file: File) => Promise<ActionResult>;
|
uploadLicense: (file: File) => Promise<ActionResult>;
|
||||||
@@ -280,7 +281,7 @@ export default class LicenseSettings extends React.PureComponent<Props, State> {
|
|||||||
);
|
);
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {license, upgradedFromTE, isDisabled} = this.props;
|
const {license, upgradedFromTE, isDisabled, isMySql} = this.props;
|
||||||
|
|
||||||
let leftPanel = null;
|
let leftPanel = null;
|
||||||
let rightPanel = null;
|
let rightPanel = null;
|
||||||
@@ -362,6 +363,7 @@ export default class LicenseSettings extends React.PureComponent<Props, State> {
|
|||||||
/>
|
/>
|
||||||
{!this.state.clickNormalUpgradeBtn && license.IsLicensed !== 'true' &&
|
{!this.state.clickNormalUpgradeBtn && license.IsLicensed !== 'true' &&
|
||||||
this.props.prevTrialLicense?.IsLicensed !== 'true' &&
|
this.props.prevTrialLicense?.IsLicensed !== 'true' &&
|
||||||
|
!isMySql &&
|
||||||
<TrialBanner
|
<TrialBanner
|
||||||
isDisabled={isDisabled}
|
isDisabled={isDisabled}
|
||||||
gettingTrialResponseCode={this.state.gettingTrialResponseCode}
|
gettingTrialResponseCode={this.state.gettingTrialResponseCode}
|
||||||
|
|||||||
@@ -367,7 +367,7 @@ const TrialBanner = ({
|
|||||||
title={
|
title={
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id='licensingPage.infoBanner.startTrialTitle'
|
id='licensingPage.infoBanner.startTrialTitle'
|
||||||
defaultMessage='Start a free 30-day tral of Mattermost Enterprise Advanced'
|
defaultMessage='Start a free 30-day trial of Mattermost Enterprise Advanced'
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
message={
|
message={
|
||||||
|
|||||||
@@ -266,6 +266,43 @@ describe('components/sidebar/show_start_trial_modal', () => {
|
|||||||
expect(mockDispatch).toHaveBeenCalledTimes(0);
|
expect(mockDispatch).toHaveBeenCalledTimes(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('should NOT dispatch the modal when database is MySQL', () => {
|
||||||
|
const isAdminUser = {
|
||||||
|
currentUserId: 'current_user_id',
|
||||||
|
profiles: {
|
||||||
|
current_user_id: {roles: 'system_admin system_user'},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const moreThan10Users = 11;
|
||||||
|
jest.spyOn(getTotalUsersHook, 'default').mockImplementation(() => moreThan10Users);
|
||||||
|
|
||||||
|
const notPreviouslyLicensed = {
|
||||||
|
prevTrialLicense: {
|
||||||
|
IsLicensed: 'false',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const moreThan6HoursWithMySQL = {
|
||||||
|
config: {
|
||||||
|
|
||||||
|
// installation date is set to be 10 hours before current time
|
||||||
|
InstallationDate: new Date().getTime() - ((10 * 60 * 60) * 1000),
|
||||||
|
SQLDriverName: 'mysql',
|
||||||
|
},
|
||||||
|
license: {
|
||||||
|
IsLicensed: 'false',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
mockState = {...mockState, entities: {...mockState.entities, users: isAdminUser, admin: notPreviouslyLicensed, general: moreThan6HoursWithMySQL}};
|
||||||
|
|
||||||
|
mount(
|
||||||
|
<ShowStartTrialModal/>,
|
||||||
|
);
|
||||||
|
expect(mockDispatch).toHaveBeenCalledTimes(0);
|
||||||
|
});
|
||||||
|
|
||||||
test('should dispatch the modal when there are more than 10 users', () => {
|
test('should dispatch the modal when there are more than 10 users', () => {
|
||||||
const isAdminUser = {
|
const isAdminUser = {
|
||||||
currentUserId: 'current_user_id',
|
currentUserId: 'current_user_id',
|
||||||
@@ -288,6 +325,7 @@ describe('components/sidebar/show_start_trial_modal', () => {
|
|||||||
|
|
||||||
// installation date is set to be 10 hours before current time
|
// installation date is set to be 10 hours before current time
|
||||||
InstallationDate: new Date().getTime() - ((10 * 60 * 60) * 1000),
|
InstallationDate: new Date().getTime() - ((10 * 60 * 60) * 1000),
|
||||||
|
SQLDriverName: 'postgres',
|
||||||
},
|
},
|
||||||
license: {
|
license: {
|
||||||
IsLicensed: 'false',
|
IsLicensed: 'false',
|
||||||
|
|||||||
@@ -35,7 +35,9 @@ const ShowStartTrialModal = () => {
|
|||||||
|
|
||||||
const isBenefitsModalOpened = useSelector((state: GlobalState) => isModalOpen(state, ModalIdentifiers.TRIAL_BENEFITS_MODAL));
|
const isBenefitsModalOpened = useSelector((state: GlobalState) => isModalOpen(state, ModalIdentifiers.TRIAL_BENEFITS_MODAL));
|
||||||
|
|
||||||
const installationDate = useSelector((state: GlobalState) => getConfig(state).InstallationDate);
|
const config = useSelector((state: GlobalState) => getConfig(state));
|
||||||
|
const installationDate = config.InstallationDate;
|
||||||
|
const isMySql = config.SQLDriverName === 'mysql';
|
||||||
const currentUser = useSelector((state: GlobalState) => getCurrentUser(state));
|
const currentUser = useSelector((state: GlobalState) => getCurrentUser(state));
|
||||||
const hadAdminDismissedModal = useSelector((state: GlobalState) => getBool(state, Preferences.START_TRIAL_MODAL, Constants.TRIAL_MODAL_AUTO_SHOWN));
|
const hadAdminDismissedModal = useSelector((state: GlobalState) => getBool(state, Preferences.START_TRIAL_MODAL, Constants.TRIAL_MODAL_AUTO_SHOWN));
|
||||||
|
|
||||||
@@ -74,7 +76,7 @@ const ShowStartTrialModal = () => {
|
|||||||
const now = new Date().getTime();
|
const now = new Date().getTime();
|
||||||
const hasEnvMoreThan6Hours = now > installationDatePlus6Hours;
|
const hasEnvMoreThan6Hours = now > installationDatePlus6Hours;
|
||||||
const hasEnvMoreThan10Users = Number(totalUsers) > userThreshold;
|
const hasEnvMoreThan10Users = Number(totalUsers) > userThreshold;
|
||||||
if (isUserAdmin && !isBenefitsModalOpened && hasEnvMoreThan10Users && hasEnvMoreThan6Hours && !hadAdminDismissedModal && !isLicensedOrPreviousLicensed) {
|
if (isUserAdmin && !isMySql && !isBenefitsModalOpened && hasEnvMoreThan10Users && hasEnvMoreThan6Hours && !hadAdminDismissedModal && !isLicensedOrPreviousLicensed) {
|
||||||
openStartTrialFormModal({trackingLocation: 'show_start_trial_modal'}, handleOnClose);
|
openStartTrialFormModal({trackingLocation: 'show_start_trial_modal'}, handleOnClose);
|
||||||
trackEvent(
|
trackEvent(
|
||||||
TELEMETRY_CATEGORIES.SELF_HOSTED_START_TRIAL_AUTO_MODAL,
|
TELEMETRY_CATEGORIES.SELF_HOSTED_START_TRIAL_AUTO_MODAL,
|
||||||
|
|||||||
@@ -4471,7 +4471,7 @@
|
|||||||
"leave_team_modal.no": "No",
|
"leave_team_modal.no": "No",
|
||||||
"leave_team_modal.title": "Leave the team?",
|
"leave_team_modal.title": "Leave the team?",
|
||||||
"leave_team_modal.yes": "Yes",
|
"leave_team_modal.yes": "Yes",
|
||||||
"licensingPage.infoBanner.startTrialTitle": "Start a free 30-day tral of Mattermost Enterprise Advanced",
|
"licensingPage.infoBanner.startTrialTitle": "Start a free 30-day trial of Mattermost Enterprise Advanced",
|
||||||
"licensingPage.overageUsersBanner.cta": "Contact Sales",
|
"licensingPage.overageUsersBanner.cta": "Contact Sales",
|
||||||
"licensingPage.overageUsersBanner.noticeDescription": "Notify your Customer Success Manager on your next true-up check. <a></a>",
|
"licensingPage.overageUsersBanner.noticeDescription": "Notify your Customer Success Manager on your next true-up check. <a></a>",
|
||||||
"licensingPage.overageUsersBanner.noticeTitle": "Your workspace user count has exceeded your licensed seat count by {seats, number} {seats, plural, one {seat} other {seats}}",
|
"licensingPage.overageUsersBanner.noticeTitle": "Your workspace user count has exceeded your licensed seat count by {seats, number} {seats, plural, one {seat} other {seats}}",
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user