Premium SKU (#30396)
* Added premium SKU * removed duplicate enterprise license check functions * Added license check on API layer * lint fix * lint fix * refactured signature: * test: Add comprehensive tests for license tier check functions * fixed test * text update * optimised license checks * fixedf test * Updated license valid function * webapp license checks * handling prekium SKU in webappp: * added plugin api method and general refactoring * Updated tests --------- Co-authored-by: Mattermost Build <build@mattermost.com>
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
21ca303b5e
Коммит
a9f09cadc2
@@ -2453,7 +2453,7 @@ func convertGroupMessageToChannel(c *Context, w http.ResponseWriter, r *http.Req
|
|||||||
}
|
}
|
||||||
|
|
||||||
func canEditChannelBanner(license *model.License, originalChannel *model.Channel) *model.AppError {
|
func canEditChannelBanner(license *model.License, originalChannel *model.Channel) *model.AppError {
|
||||||
if license == nil || !license.IsE20OrEnterprise() {
|
if !model.MinimumPremiumLicense(license) {
|
||||||
return model.NewAppError("", "license_error.feature_unavailable", nil, "feature is not available for the current license", http.StatusForbidden)
|
return model.NewAppError("", "license_error.feature_unavailable", nil, "feature is not available for the current license", http.StatusForbidden)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -810,7 +810,7 @@ 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) {
|
||||||
client.Logout(context.Background())
|
client.Logout(context.Background())
|
||||||
th.LoginBasic()
|
th.LoginBasic()
|
||||||
th.App.Srv().SetLicense(model.NewTestLicenseSKU(model.LicenseShortSkuEnterprise))
|
th.App.Srv().SetLicense(model.NewTestLicenseSKU(model.LicenseShortSkuPremium))
|
||||||
defer func() {
|
defer func() {
|
||||||
th.App.Srv().RemoveLicense()
|
th.App.Srv().RemoveLicense()
|
||||||
}()
|
}()
|
||||||
@@ -845,7 +845,7 @@ 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) {
|
||||||
client.Logout(context.Background())
|
client.Logout(context.Background())
|
||||||
th.LoginBasic()
|
th.LoginBasic()
|
||||||
th.App.Srv().SetLicense(model.NewTestLicenseSKU(model.LicenseShortSkuEnterprise))
|
th.App.Srv().SetLicense(model.NewTestLicenseSKU(model.LicenseShortSkuPremium))
|
||||||
defer func() {
|
defer func() {
|
||||||
th.App.Srv().RemoveLicense()
|
th.App.Srv().RemoveLicense()
|
||||||
}()
|
}()
|
||||||
@@ -905,7 +905,7 @@ func TestPatchChannel(t *testing.T) {
|
|||||||
t.Run("Cannot configure channel banner on a DM channel", func(t *testing.T) {
|
t.Run("Cannot configure channel banner on a DM channel", func(t *testing.T) {
|
||||||
client.Logout(context.Background())
|
client.Logout(context.Background())
|
||||||
th.LoginBasic()
|
th.LoginBasic()
|
||||||
th.App.Srv().SetLicense(model.NewTestLicenseSKU(model.LicenseShortSkuEnterprise))
|
th.App.Srv().SetLicense(model.NewTestLicenseSKU(model.LicenseShortSkuPremium))
|
||||||
defer func() {
|
defer func() {
|
||||||
th.App.Srv().RemoveLicense()
|
th.App.Srv().RemoveLicense()
|
||||||
}()
|
}()
|
||||||
@@ -932,7 +932,7 @@ func TestPatchChannel(t *testing.T) {
|
|||||||
t.Run("Cannot configure channel banner on a GM channel", func(t *testing.T) {
|
t.Run("Cannot configure channel banner on a GM channel", func(t *testing.T) {
|
||||||
client.Logout(context.Background())
|
client.Logout(context.Background())
|
||||||
th.LoginBasic()
|
th.LoginBasic()
|
||||||
th.App.Srv().SetLicense(model.NewTestLicenseSKU(model.LicenseShortSkuEnterprise))
|
th.App.Srv().SetLicense(model.NewTestLicenseSKU(model.LicenseShortSkuPremium))
|
||||||
defer func() {
|
defer func() {
|
||||||
th.App.Srv().RemoveLicense()
|
th.App.Srv().RemoveLicense()
|
||||||
}()
|
}()
|
||||||
@@ -5728,7 +5728,7 @@ func TestCanEditChannelBanner(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
t.Run("when channel type is direct message", func(t *testing.T) {
|
t.Run("when channel type is direct message", func(t *testing.T) {
|
||||||
license := model.NewTestLicenseSKU(model.LicenseShortSkuEnterprise)
|
license := model.NewTestLicenseSKU(model.LicenseShortSkuPremium)
|
||||||
channel := &model.Channel{
|
channel := &model.Channel{
|
||||||
Type: model.ChannelTypeDirect,
|
Type: model.ChannelTypeDirect,
|
||||||
}
|
}
|
||||||
@@ -5741,7 +5741,7 @@ func TestCanEditChannelBanner(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
t.Run("when channel type is group message", func(t *testing.T) {
|
t.Run("when channel type is group message", func(t *testing.T) {
|
||||||
license := model.NewTestLicenseSKU(model.LicenseShortSkuEnterprise)
|
license := model.NewTestLicenseSKU(model.LicenseShortSkuPremium)
|
||||||
channel := &model.Channel{
|
channel := &model.Channel{
|
||||||
Type: model.ChannelTypeGroup,
|
Type: model.ChannelTypeGroup,
|
||||||
}
|
}
|
||||||
@@ -5753,7 +5753,7 @@ func TestCanEditChannelBanner(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
t.Run("when channel type is open and license is valid", func(t *testing.T) {
|
t.Run("when channel type is open and license is valid", func(t *testing.T) {
|
||||||
license := model.NewTestLicenseSKU(model.LicenseShortSkuEnterprise)
|
license := model.NewTestLicenseSKU(model.LicenseShortSkuPremium)
|
||||||
channel := &model.Channel{
|
channel := &model.Channel{
|
||||||
Type: model.ChannelTypeOpen,
|
Type: model.ChannelTypeOpen,
|
||||||
}
|
}
|
||||||
@@ -5763,7 +5763,7 @@ func TestCanEditChannelBanner(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
t.Run("when channel type is private and license is valid", func(t *testing.T) {
|
t.Run("when channel type is private and license is valid", func(t *testing.T) {
|
||||||
license := model.NewTestLicenseSKU(model.LicenseShortSkuEnterprise)
|
license := model.NewTestLicenseSKU(model.LicenseShortSkuPremium)
|
||||||
channel := &model.Channel{
|
channel := &model.Channel{
|
||||||
Type: model.ChannelTypePrivate,
|
Type: model.ChannelTypePrivate,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ func (api *API) InitCustomProfileAttributes() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func listCPAFields(c *Context, w http.ResponseWriter, r *http.Request) {
|
func listCPAFields(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||||
if c.App.Channels().License() == nil || !c.App.Channels().License().IsE20OrEnterprise() {
|
if !model.MinimumEnterpriseLicense(c.App.Channels().License()) {
|
||||||
c.Err = model.NewAppError("Api4.listCPAFields", "api.custom_profile_attributes.license_error", nil, "", http.StatusForbidden)
|
c.Err = model.NewAppError("Api4.listCPAFields", "api.custom_profile_attributes.license_error", nil, "", http.StatusForbidden)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -49,7 +49,7 @@ func createCPAField(c *Context, w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.App.Channels().License() == nil || !c.App.Channels().License().IsE20OrEnterprise() {
|
if !model.MinimumEnterpriseLicense(c.App.Channels().License()) {
|
||||||
c.Err = model.NewAppError("Api4.createCPAField", "api.custom_profile_attributes.license_error", nil, "", http.StatusForbidden)
|
c.Err = model.NewAppError("Api4.createCPAField", "api.custom_profile_attributes.license_error", nil, "", http.StatusForbidden)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -89,7 +89,7 @@ func patchCPAField(c *Context, w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.App.Channels().License() == nil || !c.App.Channels().License().IsE20OrEnterprise() {
|
if !model.MinimumEnterpriseLicense(c.App.Channels().License()) {
|
||||||
c.Err = model.NewAppError("Api4.patchCPAField", "api.custom_profile_attributes.license_error", nil, "", http.StatusForbidden)
|
c.Err = model.NewAppError("Api4.patchCPAField", "api.custom_profile_attributes.license_error", nil, "", http.StatusForbidden)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -151,7 +151,7 @@ func deleteCPAField(c *Context, w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.App.Channels().License() == nil || !c.App.Channels().License().IsE20OrEnterprise() {
|
if !model.MinimumEnterpriseLicense(c.App.Channels().License()) {
|
||||||
c.Err = model.NewAppError("Api4.deleteCPAField", "api.custom_profile_attributes.license_error", nil, "", http.StatusForbidden)
|
c.Err = model.NewAppError("Api4.deleteCPAField", "api.custom_profile_attributes.license_error", nil, "", http.StatusForbidden)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -255,7 +255,7 @@ func sanitizePropertyValue(cpaField *model.CPAField, rawValue json.RawMessage) (
|
|||||||
}
|
}
|
||||||
|
|
||||||
func patchCPAValues(c *Context, w http.ResponseWriter, r *http.Request) {
|
func patchCPAValues(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||||
if c.App.Channels().License() == nil || !c.App.Channels().License().IsE20OrEnterprise() {
|
if !model.MinimumEnterpriseLicense(c.App.Channels().License()) {
|
||||||
c.Err = model.NewAppError("Api4.patchCPAValues", "api.custom_profile_attributes.license_error", nil, "", http.StatusForbidden)
|
c.Err = model.NewAppError("Api4.patchCPAValues", "api.custom_profile_attributes.license_error", nil, "", http.StatusForbidden)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -327,7 +327,7 @@ func patchCPAValues(c *Context, w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func listCPAValues(c *Context, w http.ResponseWriter, r *http.Request) {
|
func listCPAValues(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||||
if c.App.Channels().License() == nil || !c.App.Channels().License().IsE20OrEnterprise() {
|
if !model.MinimumEnterpriseLicense(c.App.Channels().License()) {
|
||||||
c.Err = model.NewAppError("Api4.listCPAValues", "api.custom_profile_attributes.license_error", nil, "", http.StatusForbidden)
|
c.Err = model.NewAppError("Api4.listCPAValues", "api.custom_profile_attributes.license_error", nil, "", http.StatusForbidden)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1482,7 +1482,7 @@ func licensedAndConfiguredForGroupBySource(app *app.App, source model.GroupSourc
|
|||||||
return model.NewAppError("", "api.ldap_groups.license_error", nil, "", http.StatusForbidden)
|
return model.NewAppError("", "api.ldap_groups.license_error", nil, "", http.StatusForbidden)
|
||||||
}
|
}
|
||||||
|
|
||||||
if source == model.GroupSourceCustom && lic.SkuShortName != model.LicenseShortSkuProfessional && lic.SkuShortName != model.LicenseShortSkuEnterprise {
|
if source == model.GroupSourceCustom && !model.MinimumProfessionalLicense(lic) {
|
||||||
return model.NewAppError("", "api.custom_groups.license_error", nil, "", http.StatusBadRequest)
|
return model.NewAppError("", "api.custom_groups.license_error", nil, "", http.StatusBadRequest)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -238,10 +238,6 @@ func requireLicense(c *Context) *model.AppError {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func minimumProfessionalLicense(c *Context) *model.AppError {
|
|
||||||
return model.MinimumProfessionalProvidedLicense(c.App.Srv().License())
|
|
||||||
}
|
|
||||||
|
|
||||||
func setHandlerOpts(handler *web.Handler, opts ...APIHandlerOption) {
|
func setHandlerOpts(handler *web.Handler, opts ...APIHandlerOption) {
|
||||||
if len(opts) == 0 {
|
if len(opts) == 0 {
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -21,7 +21,9 @@ func (api *API) InitIPFiltering() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func ensureIPFilteringInterface(c *Context, where string) (einterfaces.IPFilteringInterface, bool) {
|
func ensureIPFilteringInterface(c *Context, where string) (einterfaces.IPFilteringInterface, bool) {
|
||||||
if c.App.IPFiltering() == nil || !c.App.Config().FeatureFlags.CloudIPFiltering || c.App.License() == nil || !c.App.License().IsCloud() || c.App.License().SkuShortName != model.LicenseShortSkuEnterprise {
|
license := c.App.License()
|
||||||
|
ipFilteringFeatureFlag := c.App.Config().FeatureFlags.CloudIPFiltering
|
||||||
|
if c.App.IPFiltering() == nil || !ipFilteringFeatureFlag || license == nil || !license.IsCloud() || !model.MinimumEnterpriseLicense(license) {
|
||||||
c.Err = model.NewAppError(where, "api.context.ip_filtering.not_available.app_error", nil, "", http.StatusNotImplemented)
|
c.Err = model.NewAppError(where, "api.context.ip_filtering.not_available.app_error", nil, "", http.StatusNotImplemented)
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ func ensureOutgoingOAuthConnectionInterface(c *Context, where string) (einterfac
|
|||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.App.OutgoingOAuthConnections() == nil || c.App.License() == nil || c.App.License().SkuShortName != model.LicenseShortSkuEnterprise {
|
if c.App.OutgoingOAuthConnections() == nil || !model.MinimumEnterpriseLicense(c.App.License()) {
|
||||||
c.Err = model.NewAppError(where, "api.license.upgrade_needed.app_error", nil, "", http.StatusNotImplemented)
|
c.Err = model.NewAppError(where, "api.license.upgrade_needed.app_error", nil, "", http.StatusNotImplemented)
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1083,11 +1083,11 @@ func unpinPost(c *Context, w http.ResponseWriter, _ *http.Request) {
|
|||||||
|
|
||||||
func acknowledgePost(c *Context, w http.ResponseWriter, r *http.Request) {
|
func acknowledgePost(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||||
// license check
|
// license check
|
||||||
permissionErr := minimumProfessionalLicense(c)
|
if !model.MinimumProfessionalLicense(c.App.Srv().License()) {
|
||||||
if permissionErr != nil {
|
c.Err = model.NewAppError("", model.NoTranslation, nil, "feature is not available for the current license", http.StatusNotImplemented)
|
||||||
c.Err = permissionErr
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
c.RequirePostId().RequireUserId()
|
c.RequirePostId().RequireUserId()
|
||||||
if c.Err != nil {
|
if c.Err != nil {
|
||||||
return
|
return
|
||||||
@@ -1122,11 +1122,11 @@ func acknowledgePost(c *Context, w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
func unacknowledgePost(c *Context, w http.ResponseWriter, r *http.Request) {
|
func unacknowledgePost(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||||
// license check
|
// license check
|
||||||
permissionErr := minimumProfessionalLicense(c)
|
if !model.MinimumProfessionalLicense(c.App.Srv().License()) {
|
||||||
if permissionErr != nil {
|
c.Err = model.NewAppError("", "license_error.feature_unavailable", nil, "feature is not available for the current license", http.StatusNotImplemented)
|
||||||
c.Err = permissionErr
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
c.RequirePostId().RequireUserId()
|
c.RequirePostId().RequireUserId()
|
||||||
if c.Err != nil {
|
if c.Err != nil {
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -1465,7 +1465,7 @@ func (a *App) allowChannelMentions(c request.CTX, post *model.Post, numProfiles
|
|||||||
|
|
||||||
// allowGroupMentions returns whether or not the group mentions are allowed for the given post.
|
// allowGroupMentions returns whether or not the group mentions are allowed for the given post.
|
||||||
func (a *App) allowGroupMentions(c request.CTX, post *model.Post) bool {
|
func (a *App) allowGroupMentions(c request.CTX, post *model.Post) bool {
|
||||||
if license := a.Srv().License(); license == nil || (license.SkuShortName != model.LicenseShortSkuProfessional && license.SkuShortName != model.LicenseShortSkuEnterprise) {
|
if !model.MinimumProfessionalLicense(a.Srv().License()) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -670,7 +670,6 @@ func (a *App) mergePrepackagedPlugins(remoteMarketplacePlugins map[string]*model
|
|||||||
return model.NewAppError("mergePrepackagedPlugins", "app.plugin.config.app_error", nil, "", http.StatusInternalServerError)
|
return model.NewAppError("mergePrepackagedPlugins", "app.plugin.config.app_error", nil, "", http.StatusInternalServerError)
|
||||||
}
|
}
|
||||||
|
|
||||||
isEnterpriseLicense := a.License() != nil && a.License().IsE20OrEnterprise()
|
|
||||||
for _, prepackaged := range pluginsEnvironment.PrepackagedPlugins() {
|
for _, prepackaged := range pluginsEnvironment.PrepackagedPlugins() {
|
||||||
if prepackaged.Manifest == nil {
|
if prepackaged.Manifest == nil {
|
||||||
continue
|
continue
|
||||||
@@ -687,7 +686,7 @@ func (a *App) mergePrepackagedPlugins(remoteMarketplacePlugins map[string]*model
|
|||||||
|
|
||||||
// If not enterprise, check version.
|
// If not enterprise, check version.
|
||||||
// Playbooks is not listed in the marketplace, this only handles prepackaged.
|
// Playbooks is not listed in the marketplace, this only handles prepackaged.
|
||||||
if !isEnterpriseLicense {
|
if !model.MinimumEnterpriseLicense(a.License()) {
|
||||||
if prepackaged.Manifest.Id == model.PluginIdPlaybooks {
|
if prepackaged.Manifest.Id == model.PluginIdPlaybooks {
|
||||||
version, err := semver.Parse(prepackaged.Manifest.Version)
|
version, err := semver.Parse(prepackaged.Manifest.Version)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -1033,8 +1032,8 @@ func (ch *Channels) processPrepackagedPlugin(pluginPath *pluginSignaturePath) (*
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrapf(err, "Unable to verify prepackaged playbooks version")
|
return nil, errors.Wrapf(err, "Unable to verify prepackaged playbooks version")
|
||||||
}
|
}
|
||||||
license := ch.License()
|
|
||||||
hasEnterpriseLicense := license != nil && license.IsE20OrEnterprise()
|
hasEnterpriseLicense := model.MinimumEnterpriseLicense(ch.License())
|
||||||
|
|
||||||
// Do not install playbooks >=v2 if we do not have an enterprise license
|
// Do not install playbooks >=v2 if we do not have an enterprise license
|
||||||
if version.GTE(SemVerV2) && !hasEnterpriseLicense {
|
if version.GTE(SemVerV2) && !hasEnterpriseLicense {
|
||||||
@@ -1105,15 +1104,13 @@ func (ch *Channels) pluginIsTransitionallyPrepackaged(m *model.Manifest) bool {
|
|||||||
// - the server is not enterprise licensed
|
// - the server is not enterprise licensed
|
||||||
// - the playbooks version is <v2
|
// - the playbooks version is <v2
|
||||||
func (ch *Channels) playbooksIsTransitionallyPrepackaged(m *model.Manifest) bool {
|
func (ch *Channels) playbooksIsTransitionallyPrepackaged(m *model.Manifest) bool {
|
||||||
license := ch.srv.License()
|
|
||||||
isNotEnterpriseLicensed := !(license != nil && license.IsE20OrEnterprise())
|
|
||||||
version, err := semver.Parse(m.Version)
|
version, err := semver.Parse(m.Version)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ch.srv.Log().Warn("unable to parse prepackaged playbooks version - not marking it as transitional.", mlog.String("version", m.Version), mlog.Err(err))
|
ch.srv.Log().Warn("unable to parse prepackaged playbooks version - not marking it as transitional.", mlog.String("version", m.Version), mlog.Err(err))
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
return isNotEnterpriseLicensed && version.LT(SemVerV2)
|
return !model.MinimumEnterpriseLicense(ch.srv.License()) && version.LT(SemVerV2)
|
||||||
}
|
}
|
||||||
|
|
||||||
// shouldPersistTransitionallyPrepackagedPlugin determines if a transitionally prepackaged plugin
|
// shouldPersistTransitionallyPrepackagedPlugin determines if a transitionally prepackaged plugin
|
||||||
|
|||||||
@@ -55,16 +55,14 @@ func postPriorityCheck(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ack := priority.RequestedAck; ack != nil && *ack {
|
if ack := priority.RequestedAck; ack != nil && *ack {
|
||||||
licenseErr := model.MinimumProfessionalProvidedLicense(license)
|
if !model.MinimumProfessionalLicense(license) {
|
||||||
if licenseErr != nil {
|
return model.NewAppError("", "license_error.feature_unavailable", nil, "feature is not available for the current license", http.StatusNotImplemented)
|
||||||
return licenseErr
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if notification := priority.PersistentNotifications; notification != nil && *notification {
|
if notification := priority.PersistentNotifications; notification != nil && *notification {
|
||||||
licenseErr := model.MinimumProfessionalProvidedLicense(license)
|
if !model.MinimumProfessionalLicense(license) {
|
||||||
if licenseErr != nil {
|
return model.NewAppError("", "license_error.feature_unavailable", nil, "feature is not available for the current license", http.StatusNotImplemented)
|
||||||
return licenseErr
|
|
||||||
}
|
}
|
||||||
if !isPersistentNotificationsEnabled {
|
if !isPersistentNotificationsEnabled {
|
||||||
return priorityForbiddenErr
|
return priorityForbiddenErr
|
||||||
|
|||||||
@@ -199,7 +199,7 @@ func (a *App) GetUserCountForReport(filter *model.UserReportOptions) (*int64, *m
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) StartUsersBatchExport(rctx request.CTX, ro *model.UserReportOptions, startAt int64, endAt int64) *model.AppError {
|
func (a *App) StartUsersBatchExport(rctx request.CTX, ro *model.UserReportOptions, startAt int64, endAt int64) *model.AppError {
|
||||||
if license := a.Srv().License(); license == nil || (license.SkuShortName != model.LicenseShortSkuProfessional && license.SkuShortName != model.LicenseShortSkuEnterprise) {
|
if !model.MinimumProfessionalLicense(a.Srv().License()) {
|
||||||
return model.NewAppError("StartUsersBatchExport", "app.report.start_users_batch_export.license_error", nil, "", http.StatusBadRequest)
|
return model.NewAppError("StartUsersBatchExport", "app.report.start_users_batch_export.license_error", nil, "", http.StatusBadRequest)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,8 +21,7 @@ func (scheduler *Scheduler) NextScheduleTime(cfg *model.Config, _ time.Time, _ b
|
|||||||
|
|
||||||
func MakeScheduler(jobServer *jobs.JobServer, licenseFunc func() *model.License) *Scheduler {
|
func MakeScheduler(jobServer *jobs.JobServer, licenseFunc func() *model.License) *Scheduler {
|
||||||
enabledFunc := func(_ *model.Config) bool {
|
enabledFunc := func(_ *model.Config) bool {
|
||||||
l := licenseFunc()
|
return model.MinimumProfessionalLicense(licenseFunc())
|
||||||
return l != nil && (l.SkuShortName == model.LicenseShortSkuProfessional || l.SkuShortName == model.LicenseShortSkuEnterprise)
|
|
||||||
}
|
}
|
||||||
return &Scheduler{jobs.NewPeriodicScheduler(jobServer, model.JobTypePostPersistentNotifications, 0, enabledFunc)}
|
return &Scheduler{jobs.NewPeriodicScheduler(jobServer, model.JobTypePostPersistentNotifications, 0, enabledFunc)}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -226,7 +226,7 @@ func GenerateClientConfig(c *model.Config, telemetryID string, license *model.Li
|
|||||||
props["ExperimentalRemoteClusterService"] = strconv.FormatBool(c.FeatureFlags.EnableRemoteClusterService && *c.ConnectedWorkspacesSettings.EnableRemoteClusterService)
|
props["ExperimentalRemoteClusterService"] = strconv.FormatBool(c.FeatureFlags.EnableRemoteClusterService && *c.ConnectedWorkspacesSettings.EnableRemoteClusterService)
|
||||||
}
|
}
|
||||||
|
|
||||||
if license.SkuShortName == model.LicenseShortSkuProfessional || license.SkuShortName == model.LicenseShortSkuEnterprise {
|
if model.MinimumProfessionalLicense(license) {
|
||||||
props["EnableCustomGroups"] = strconv.FormatBool(*c.ServiceSettings.EnableCustomGroups)
|
props["EnableCustomGroups"] = strconv.FormatBool(*c.ServiceSettings.EnableCustomGroups)
|
||||||
props["PostAcknowledgements"] = "true"
|
props["PostAcknowledgements"] = "true"
|
||||||
props["ScheduledPosts"] = strconv.FormatBool(*c.ServiceSettings.ScheduledPosts)
|
props["ScheduledPosts"] = strconv.FormatBool(*c.ServiceSettings.ScheduledPosts)
|
||||||
|
|||||||
@@ -99,6 +99,7 @@ type TrackSKU string
|
|||||||
const (
|
const (
|
||||||
TrackProfessionalSKU TrackSKU = "professional"
|
TrackProfessionalSKU TrackSKU = "professional"
|
||||||
TrackEnterpriseSKU TrackSKU = "enterprise"
|
TrackEnterpriseSKU TrackSKU = "enterprise"
|
||||||
|
TrackPremiumSKU TrackSKU = "premium"
|
||||||
)
|
)
|
||||||
|
|
||||||
type TrackFeature string
|
type TrackFeature string
|
||||||
|
|||||||
@@ -23,8 +23,19 @@ const (
|
|||||||
LicenseShortSkuE20 = "E20"
|
LicenseShortSkuE20 = "E20"
|
||||||
LicenseShortSkuProfessional = "professional"
|
LicenseShortSkuProfessional = "professional"
|
||||||
LicenseShortSkuEnterprise = "enterprise"
|
LicenseShortSkuEnterprise = "enterprise"
|
||||||
|
LicenseShortSkuPremium = "premium"
|
||||||
|
|
||||||
|
ProfessionalTier = 10
|
||||||
|
EnterpriseTier = 20
|
||||||
|
PremiumTier = 30
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var LicenseToLicenseTier = map[string]int{
|
||||||
|
LicenseShortSkuProfessional: ProfessionalTier,
|
||||||
|
LicenseShortSkuEnterprise: EnterpriseTier,
|
||||||
|
LicenseShortSkuPremium: PremiumTier,
|
||||||
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
LicenseUpForRenewalEmailSent = "LicenseUpForRenewalEmailSent"
|
LicenseUpForRenewalEmailSent = "LicenseUpForRenewalEmailSent"
|
||||||
)
|
)
|
||||||
@@ -356,8 +367,7 @@ func (l *License) IsSanctionedTrial() bool {
|
|||||||
func (l *License) HasEnterpriseMarketplacePlugins() bool {
|
func (l *License) HasEnterpriseMarketplacePlugins() bool {
|
||||||
return *l.Features.EnterprisePlugins ||
|
return *l.Features.EnterprisePlugins ||
|
||||||
l.SkuShortName == LicenseShortSkuE20 ||
|
l.SkuShortName == LicenseShortSkuE20 ||
|
||||||
l.SkuShortName == LicenseShortSkuProfessional ||
|
MinimumProfessionalLicense(l)
|
||||||
l.SkuShortName == LicenseShortSkuEnterprise
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *License) HasRemoteClusterService() bool {
|
func (l *License) HasRemoteClusterService() bool {
|
||||||
@@ -371,8 +381,7 @@ func (l *License) HasRemoteClusterService() bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (l.Features != nil && l.Features.RemoteClusterService != nil && *l.Features.RemoteClusterService) ||
|
return (l.Features != nil && l.Features.RemoteClusterService != nil && *l.Features.RemoteClusterService) ||
|
||||||
l.SkuShortName == LicenseShortSkuProfessional ||
|
MinimumProfessionalLicense(l)
|
||||||
l.SkuShortName == LicenseShortSkuEnterprise
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *License) HasSharedChannels() bool {
|
func (l *License) HasSharedChannels() bool {
|
||||||
@@ -381,13 +390,7 @@ func (l *License) HasSharedChannels() bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (l.Features != nil && l.Features.SharedChannels != nil && *l.Features.SharedChannels) ||
|
return (l.Features != nil && l.Features.SharedChannels != nil && *l.Features.SharedChannels) ||
|
||||||
l.SkuShortName == LicenseShortSkuProfessional ||
|
MinimumProfessionalLicense(l)
|
||||||
l.SkuShortName == LicenseShortSkuEnterprise
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsE20OrEnterprise returns true when the license is for E20 or Enterprise.
|
|
||||||
func (l *License) IsE20OrEnterprise() bool {
|
|
||||||
return l.SkuShortName == LicenseShortSkuE20 || l.SkuShortName == LicenseShortSkuEnterprise
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewTestLicense returns a license that expires in the future and has the given features.
|
// NewTestLicense returns a license that expires in the future and has the given features.
|
||||||
@@ -459,9 +462,19 @@ func (lr *LicenseRecord) PreSave() {
|
|||||||
lr.CreateAt = GetMillis()
|
lr.CreateAt = GetMillis()
|
||||||
}
|
}
|
||||||
|
|
||||||
func MinimumProfessionalProvidedLicense(license *License) *AppError {
|
// MinimumProfessionalLicense returns true if the provided license is at least a professional license.
|
||||||
if license == nil || (license.SkuShortName != LicenseShortSkuProfessional && license.SkuShortName != LicenseShortSkuEnterprise) {
|
// Higher tier licenses also satisfy the condition.
|
||||||
return NewAppError("", NoTranslation, nil, "license is neither professional nor enterprise", http.StatusNotImplemented)
|
func MinimumProfessionalLicense(license *License) bool {
|
||||||
|
return license != nil && LicenseToLicenseTier[license.SkuShortName] >= ProfessionalTier
|
||||||
}
|
}
|
||||||
return nil
|
|
||||||
|
// MinimumEnterpriseLicense returns true if the provided license is at least a enterprise license.
|
||||||
|
// Higher tier licenses also satisfy the condition.
|
||||||
|
func MinimumEnterpriseLicense(license *License) bool {
|
||||||
|
return license != nil && LicenseToLicenseTier[license.SkuShortName] >= EnterpriseTier
|
||||||
|
}
|
||||||
|
|
||||||
|
// MinimumPremiumLicense returns true if the provided license is at least a premium license.
|
||||||
|
func MinimumPremiumLicense(license *License) bool {
|
||||||
|
return license != nil && LicenseToLicenseTier[license.SkuShortName] >= PremiumTier
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -485,3 +485,189 @@ func TestLicenseHasSharedChannels(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestMinimumProfessionalLicense(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
description string
|
||||||
|
license *License
|
||||||
|
expectedValue bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
"nil license",
|
||||||
|
nil,
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"professional license",
|
||||||
|
&License{
|
||||||
|
SkuShortName: LicenseShortSkuProfessional,
|
||||||
|
},
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"enterprise license",
|
||||||
|
&License{
|
||||||
|
SkuShortName: LicenseShortSkuEnterprise,
|
||||||
|
},
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"premium license",
|
||||||
|
&License{
|
||||||
|
SkuShortName: LicenseShortSkuPremium,
|
||||||
|
},
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"E10 license",
|
||||||
|
&License{
|
||||||
|
SkuShortName: LicenseShortSkuE10,
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"E20 license",
|
||||||
|
&License{
|
||||||
|
SkuShortName: LicenseShortSkuE20,
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"unknown license",
|
||||||
|
&License{
|
||||||
|
SkuShortName: "unknown",
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, testCase := range testCases {
|
||||||
|
t.Run(testCase.description, func(t *testing.T) {
|
||||||
|
assert.Equal(t, testCase.expectedValue, MinimumProfessionalLicense(testCase.license))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMinimumEnterpriseLicense(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
description string
|
||||||
|
license *License
|
||||||
|
expectedValue bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
"nil license",
|
||||||
|
nil,
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"professional license",
|
||||||
|
&License{
|
||||||
|
SkuShortName: LicenseShortSkuProfessional,
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"enterprise license",
|
||||||
|
&License{
|
||||||
|
SkuShortName: LicenseShortSkuEnterprise,
|
||||||
|
},
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"premium license",
|
||||||
|
&License{
|
||||||
|
SkuShortName: LicenseShortSkuPremium,
|
||||||
|
},
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"E10 license",
|
||||||
|
&License{
|
||||||
|
SkuShortName: LicenseShortSkuE10,
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"E20 license",
|
||||||
|
&License{
|
||||||
|
SkuShortName: LicenseShortSkuE20,
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"unknown license",
|
||||||
|
&License{
|
||||||
|
SkuShortName: "unknown",
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, testCase := range testCases {
|
||||||
|
t.Run(testCase.description, func(t *testing.T) {
|
||||||
|
assert.Equal(t, testCase.expectedValue, MinimumEnterpriseLicense(testCase.license))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMinimumPremiumLicense(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
description string
|
||||||
|
license *License
|
||||||
|
expectedValue bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
"nil license",
|
||||||
|
nil,
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"professional license",
|
||||||
|
&License{
|
||||||
|
SkuShortName: LicenseShortSkuProfessional,
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"enterprise license",
|
||||||
|
&License{
|
||||||
|
SkuShortName: LicenseShortSkuEnterprise,
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"premium license",
|
||||||
|
&License{
|
||||||
|
SkuShortName: LicenseShortSkuPremium,
|
||||||
|
},
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"E10 license",
|
||||||
|
&License{
|
||||||
|
SkuShortName: LicenseShortSkuE10,
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"E20 license",
|
||||||
|
&License{
|
||||||
|
SkuShortName: LicenseShortSkuE20,
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"unknown license",
|
||||||
|
&License{
|
||||||
|
SkuShortName: "unknown",
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, testCase := range testCases {
|
||||||
|
t.Run(testCase.description, func(t *testing.T) {
|
||||||
|
assert.Equal(t, testCase.expectedValue, MinimumPremiumLicense(testCase.license))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -4,13 +4,6 @@ import (
|
|||||||
"github.com/mattermost/mattermost/server/public/model"
|
"github.com/mattermost/mattermost/server/public/model"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
|
||||||
e10 = "E10"
|
|
||||||
e20 = "E20"
|
|
||||||
professional = "professional"
|
|
||||||
enterprise = "enterprise"
|
|
||||||
)
|
|
||||||
|
|
||||||
// IsEnterpriseLicensedOrDevelopment returns true when the server is licensed with any Mattermost
|
// IsEnterpriseLicensedOrDevelopment returns true when the server is licensed with any Mattermost
|
||||||
// Enterprise License, or has `EnableDeveloper` and `EnableTesting` configuration settings
|
// Enterprise License, or has `EnableDeveloper` and `EnableTesting` configuration settings
|
||||||
// enabled signaling a non-production, developer mode.
|
// enabled signaling a non-production, developer mode.
|
||||||
@@ -30,7 +23,7 @@ func isValidSkuShortName(license *model.License) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch license.SkuShortName {
|
switch license.SkuShortName {
|
||||||
case e10, e20, professional, enterprise:
|
case model.LicenseShortSkuE10, model.LicenseShortSkuE20, model.LicenseShortSkuProfessional, model.LicenseShortSkuEnterprise, model.LicenseShortSkuPremium:
|
||||||
return true
|
return true
|
||||||
default:
|
default:
|
||||||
return false
|
return false
|
||||||
@@ -41,9 +34,7 @@ func isValidSkuShortName(license *model.License) bool {
|
|||||||
// Enterprise E10 License or a Mattermost Professional License, or has `EnableDeveloper` and
|
// Enterprise E10 License or a Mattermost Professional License, or has `EnableDeveloper` and
|
||||||
// `EnableTesting` configuration settings enabled, signaling a non-production, developer mode.
|
// `EnableTesting` configuration settings enabled, signaling a non-production, developer mode.
|
||||||
func IsE10LicensedOrDevelopment(config *model.Config, license *model.License) bool {
|
func IsE10LicensedOrDevelopment(config *model.Config, license *model.License) bool {
|
||||||
if license != nil &&
|
if model.MinimumProfessionalLicense(license) {
|
||||||
(license.SkuShortName == e10 || license.SkuShortName == professional ||
|
|
||||||
license.SkuShortName == e20 || license.SkuShortName == enterprise) {
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,7 +56,7 @@ func IsE10LicensedOrDevelopment(config *model.Config, license *model.License) bo
|
|||||||
// Enterprise E20 License or a Mattermost Enterprise License, or has `EnableDeveloper` and
|
// Enterprise E20 License or a Mattermost Enterprise License, or has `EnableDeveloper` and
|
||||||
// `EnableTesting` configuration settings enabled, signaling a non-production, developer mode.
|
// `EnableTesting` configuration settings enabled, signaling a non-production, developer mode.
|
||||||
func IsE20LicensedOrDevelopment(config *model.Config, license *model.License) bool {
|
func IsE20LicensedOrDevelopment(config *model.Config, license *model.License) bool {
|
||||||
if license != nil && (license.SkuShortName == e20 || license.SkuShortName == enterprise) {
|
if model.MinimumEnterpriseLicense(license) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -83,6 +74,16 @@ func IsE20LicensedOrDevelopment(config *model.Config, license *model.License) bo
|
|||||||
return IsConfiguredForDevelopment(config)
|
return IsConfiguredForDevelopment(config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsPremiumLicensedOrDevelopment returns true when the server is licensed with a Mattermost
|
||||||
|
// Premium License, or has `EnableDeveloper` and `EnableTesting` configuration settings
|
||||||
|
func IsPremiumLicensedOrDevelopment(config *model.Config, license *model.License) bool {
|
||||||
|
if license != nil && license.SkuShortName == model.LicenseShortSkuPremium {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return IsConfiguredForDevelopment(config)
|
||||||
|
}
|
||||||
|
|
||||||
// IsConfiguredForDevelopment returns true when the server has `EnableDeveloper` and `EnableTesting`
|
// IsConfiguredForDevelopment returns true when the server has `EnableDeveloper` and `EnableTesting`
|
||||||
// configuration settings enabled, signaling a non-production, developer mode.
|
// configuration settings enabled, signaling a non-production, developer mode.
|
||||||
func IsConfiguredForDevelopment(config *model.Config) bool {
|
func IsConfiguredForDevelopment(config *model.Config) bool {
|
||||||
|
|||||||
@@ -133,19 +133,6 @@ func TestIsE20LicensedOrDevelopment(t *testing.T) {
|
|||||||
Features: &model.Features{FutureFeatures: bToP(true)},
|
Features: &model.Features{FutureFeatures: bToP(true)},
|
||||||
}))
|
}))
|
||||||
})
|
})
|
||||||
t.Run("license with E20 SKU name, disabled future features", func(t *testing.T) {
|
|
||||||
assert.True(t, IsE20LicensedOrDevelopment(nil, &model.License{
|
|
||||||
SkuShortName: "E20",
|
|
||||||
Features: &model.Features{FutureFeatures: bToP(false)},
|
|
||||||
}))
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("license with E20 SKU name, enabled future features", func(t *testing.T) {
|
|
||||||
assert.True(t, IsE20LicensedOrDevelopment(nil, &model.License{
|
|
||||||
SkuShortName: "E20",
|
|
||||||
Features: &model.Features{FutureFeatures: bToP(true)},
|
|
||||||
}))
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("license with enterprise SKU name, disabled future features", func(t *testing.T) {
|
t.Run("license with enterprise SKU name, disabled future features", func(t *testing.T) {
|
||||||
assert.True(t, IsE20LicensedOrDevelopment(nil, &model.License{
|
assert.True(t, IsE20LicensedOrDevelopment(nil, &model.License{
|
||||||
@@ -229,20 +216,6 @@ func TestIsE10LicensedOrDevelopment(t *testing.T) {
|
|||||||
))
|
))
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("license with E10 SKU name, disabled LDAP", func(t *testing.T) {
|
|
||||||
assert.True(t, IsE10LicensedOrDevelopment(nil, &model.License{
|
|
||||||
SkuShortName: "E10",
|
|
||||||
Features: &model.Features{LDAP: bToP(false)},
|
|
||||||
}))
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("license with E10 SKU name, enabled LDAP", func(t *testing.T) {
|
|
||||||
assert.True(t, IsE10LicensedOrDevelopment(nil, &model.License{
|
|
||||||
SkuShortName: "E10",
|
|
||||||
Features: &model.Features{LDAP: bToP(true)},
|
|
||||||
}))
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("license with professional SKU name, disabled LDAP", func(t *testing.T) {
|
t.Run("license with professional SKU name, disabled LDAP", func(t *testing.T) {
|
||||||
assert.True(t, IsE10LicensedOrDevelopment(nil, &model.License{
|
assert.True(t, IsE10LicensedOrDevelopment(nil, &model.License{
|
||||||
SkuShortName: "professional",
|
SkuShortName: "professional",
|
||||||
@@ -256,19 +229,6 @@ func TestIsE10LicensedOrDevelopment(t *testing.T) {
|
|||||||
Features: &model.Features{LDAP: bToP(true)},
|
Features: &model.Features{LDAP: bToP(true)},
|
||||||
}))
|
}))
|
||||||
})
|
})
|
||||||
t.Run("license with E20 SKU name, disabled LDAP", func(t *testing.T) {
|
|
||||||
assert.True(t, IsE10LicensedOrDevelopment(nil, &model.License{
|
|
||||||
SkuShortName: "E20",
|
|
||||||
Features: &model.Features{LDAP: bToP(false)},
|
|
||||||
}))
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("license with E20 SKU name, enabled LDAP", func(t *testing.T) {
|
|
||||||
assert.True(t, IsE10LicensedOrDevelopment(nil, &model.License{
|
|
||||||
SkuShortName: "E20",
|
|
||||||
Features: &model.Features{LDAP: bToP(true)},
|
|
||||||
}))
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("license with enterprise SKU name, disabled LDAP", func(t *testing.T) {
|
t.Run("license with enterprise SKU name, disabled LDAP", func(t *testing.T) {
|
||||||
assert.True(t, IsE10LicensedOrDevelopment(nil, &model.License{
|
assert.True(t, IsE10LicensedOrDevelopment(nil, &model.License{
|
||||||
@@ -325,6 +285,88 @@ func TestIsValidSKUShortName(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestIsPremiumOrDevelopment(t *testing.T) {
|
||||||
|
t.Run("nil license features", func(t *testing.T) {
|
||||||
|
assert.False(t, IsPremiumLicensedOrDevelopment(nil, &model.License{}))
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("nil future features", func(t *testing.T) {
|
||||||
|
assert.False(t, IsPremiumLicensedOrDevelopment(nil, &model.License{Features: &model.Features{}}))
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("disabled future features", func(t *testing.T) {
|
||||||
|
assert.False(t, IsPremiumLicensedOrDevelopment(nil, &model.License{Features: &model.Features{
|
||||||
|
FutureFeatures: bToP(false),
|
||||||
|
}}))
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("should have no affect of future features", func(t *testing.T) {
|
||||||
|
assert.False(t, IsPremiumLicensedOrDevelopment(nil, &model.License{Features: &model.Features{
|
||||||
|
FutureFeatures: bToP(true),
|
||||||
|
}}))
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("no license, no config", func(t *testing.T) {
|
||||||
|
assert.False(t, IsPremiumLicensedOrDevelopment(nil, nil))
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("no license, nil config", func(t *testing.T) {
|
||||||
|
assert.False(t, IsPremiumLicensedOrDevelopment(
|
||||||
|
&model.Config{ServiceSettings: model.ServiceSettings{EnableDeveloper: nil, EnableTesting: nil}},
|
||||||
|
nil,
|
||||||
|
))
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("no license, only developer mode", func(t *testing.T) {
|
||||||
|
assert.False(t, IsPremiumLicensedOrDevelopment(
|
||||||
|
&model.Config{ServiceSettings: model.ServiceSettings{EnableDeveloper: bToP(true), EnableTesting: bToP(false)}},
|
||||||
|
nil,
|
||||||
|
))
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("no license, only testing mode", func(t *testing.T) {
|
||||||
|
assert.False(t, IsPremiumLicensedOrDevelopment(
|
||||||
|
&model.Config{ServiceSettings: model.ServiceSettings{EnableDeveloper: bToP(false), EnableTesting: bToP(true)}},
|
||||||
|
nil,
|
||||||
|
))
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("no license, developer and testing mode", func(t *testing.T) {
|
||||||
|
assert.True(t, IsPremiumLicensedOrDevelopment(
|
||||||
|
&model.Config{ServiceSettings: model.ServiceSettings{EnableDeveloper: bToP(true), EnableTesting: bToP(true)}},
|
||||||
|
nil,
|
||||||
|
))
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("license with E10 SKU name, disabled future features", func(t *testing.T) {
|
||||||
|
assert.False(t, IsPremiumLicensedOrDevelopment(nil, &model.License{
|
||||||
|
SkuShortName: "E10",
|
||||||
|
Features: &model.Features{FutureFeatures: bToP(false)},
|
||||||
|
}))
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("license with E10 SKU name, enabled future features", func(t *testing.T) {
|
||||||
|
assert.False(t, IsPremiumLicensedOrDevelopment(nil, &model.License{
|
||||||
|
SkuShortName: "E10",
|
||||||
|
Features: &model.Features{FutureFeatures: bToP(true)},
|
||||||
|
}))
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("license with E20 SKU name, disabled future features", func(t *testing.T) {
|
||||||
|
assert.False(t, IsPremiumLicensedOrDevelopment(nil, &model.License{
|
||||||
|
SkuShortName: "E20",
|
||||||
|
Features: &model.Features{FutureFeatures: bToP(false)},
|
||||||
|
}))
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("license with E20 SKU name, enabled future features", func(t *testing.T) {
|
||||||
|
assert.False(t, IsPremiumLicensedOrDevelopment(nil, &model.License{
|
||||||
|
SkuShortName: "E20",
|
||||||
|
Features: &model.Features{FutureFeatures: bToP(true)},
|
||||||
|
}))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func bToP(b bool) *bool {
|
func bToP(b bool) *bool {
|
||||||
return &b
|
return &b
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import type {ClientLicense} from '@mattermost/types/config';
|
|||||||
import ContactUsButton from 'components/announcement_bar/contact_sales/contact_us';
|
import ContactUsButton from 'components/announcement_bar/contact_sales/contact_us';
|
||||||
import SetupSystemSvg from 'components/common/svg_images_components/setup_system';
|
import SetupSystemSvg from 'components/common/svg_images_components/setup_system';
|
||||||
|
|
||||||
import {isEnterpriseOrE20License} from 'utils/license_utils';
|
import {isEnterpriseLicense} from 'utils/license_utils';
|
||||||
|
|
||||||
export interface EnterpriseEditionProps {
|
export interface EnterpriseEditionProps {
|
||||||
isTrialLicense: boolean;
|
isTrialLicense: boolean;
|
||||||
@@ -29,7 +29,7 @@ const EnterpriseEditionRightPanel = ({
|
|||||||
'And more...',
|
'And more...',
|
||||||
];
|
];
|
||||||
|
|
||||||
const isEnterpriseOrE20 = isEnterpriseOrE20License(license);
|
const isEnterpriseOrE20 = isEnterpriseLicense(license);
|
||||||
|
|
||||||
const contactSalesBtn = (
|
const contactSalesBtn = (
|
||||||
<div className='purchase-card'>
|
<div className='purchase-card'>
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ import ExternalLink from 'components/external_link';
|
|||||||
import AdminHeader from 'components/widgets/admin_console/admin_header';
|
import AdminHeader from 'components/widgets/admin_console/admin_header';
|
||||||
|
|
||||||
import {AboutLinks, CloudLinks, ModalIdentifiers} from 'utils/constants';
|
import {AboutLinks, CloudLinks, ModalIdentifiers} from 'utils/constants';
|
||||||
import {isLicenseExpired, isLicenseExpiring, isTrialLicense, isEnterpriseOrE20License, licenseSKUWithFirstLetterCapitalized} from 'utils/license_utils';
|
import {isLicenseExpired, isLicenseExpiring, isTrialLicense, licenseSKUWithFirstLetterCapitalized, isEnterpriseLicense} from 'utils/license_utils';
|
||||||
|
|
||||||
import type {ModalData} from 'types/actions';
|
import type {ModalData} from 'types/actions';
|
||||||
|
|
||||||
@@ -384,7 +384,7 @@ export default class LicenseSettings extends React.PureComponent<Props, State> {
|
|||||||
<div className='panel-card'>
|
<div className='panel-card'>
|
||||||
{rightPanel}
|
{rightPanel}
|
||||||
</div>
|
</div>
|
||||||
{!isEnterpriseOrE20License(license) && this.comparePlans}
|
{!isEnterpriseLicense(license) && this.comparePlans}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -20,13 +20,15 @@ import {getAdminConsoleUserManagementTableProperties} from 'selectors/views/admi
|
|||||||
|
|
||||||
import WithTooltip from 'components/with_tooltip';
|
import WithTooltip from 'components/with_tooltip';
|
||||||
|
|
||||||
import {LicenseSkus, ModalIdentifiers} from 'utils/constants';
|
import {ModalIdentifiers} from 'utils/constants';
|
||||||
|
import {isMinimumProfessionalLicense} from 'utils/license_utils';
|
||||||
|
|
||||||
import {ExportErrorModal} from './export_error_modal';
|
import {ExportErrorModal} from './export_error_modal';
|
||||||
import {ExportUserDataModal} from './export_user_data_modal';
|
import {ExportUserDataModal} from './export_user_data_modal';
|
||||||
import {UpgradeExportDataModal} from './upgrade_export_data_modal';
|
import {UpgradeExportDataModal} from './upgrade_export_data_modal';
|
||||||
|
|
||||||
import {convertTableOptionsToUserReportOptions} from '../utils';
|
import {convertTableOptionsToUserReportOptions} from '../utils';
|
||||||
|
|
||||||
import './system_users_export.scss';
|
import './system_users_export.scss';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
@@ -47,7 +49,7 @@ export function SystemUsersExport(props: Props) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const license = useSelector(getLicense);
|
const license = useSelector(getLicense);
|
||||||
const isLicensed = license.IsLicensed === 'true' && (license.SkuShortName === LicenseSkus.Professional || license.SkuShortName === LicenseSkus.Enterprise);
|
const isLicensed = license.IsLicensed === 'true' && isMinimumProfessionalLicense(license);
|
||||||
|
|
||||||
async function doExport(checked?: boolean) {
|
async function doExport(checked?: boolean) {
|
||||||
const {error} = await dispatch(startUsersBatchExport(tableOptionsToUserReport));
|
const {error} = await dispatch(startUsersBatchExport(tableOptionsToUserReport));
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ import {getTeam} from 'mattermost-redux/selectors/entities/teams';
|
|||||||
|
|
||||||
import {setNavigationBlocked} from 'actions/admin_actions';
|
import {setNavigationBlocked} from 'actions/admin_actions';
|
||||||
|
|
||||||
import {LicenseSkus} from 'utils/constants';
|
import {isMinimumEnterpriseLicense, isMinimumProfessionalLicense} from 'utils/license_utils';
|
||||||
|
|
||||||
import ChannelDetails from './channel_details';
|
import ChannelDetails from './channel_details';
|
||||||
|
|
||||||
@@ -54,11 +54,11 @@ function mapStateToProps(state: GlobalState, ownProps: OwnProps) {
|
|||||||
|
|
||||||
const isLicensed = license?.IsLicensed === 'true';
|
const isLicensed = license?.IsLicensed === 'true';
|
||||||
|
|
||||||
// Channel Moderation is only available for Professional, Enterprise and backward compatible with E20
|
// Channel Moderation is only available for Professional and above
|
||||||
const channelModerationEnabled = isLicensed && (license.SkuShortName === LicenseSkus.Professional || license.SkuShortName === LicenseSkus.Enterprise || license.SkuShortName === LicenseSkus.E20);
|
const channelModerationEnabled = isLicensed && isMinimumProfessionalLicense(license);
|
||||||
|
|
||||||
// Channel Groups is only available for Enterprise and backward compatible with E20
|
// Channel Groups is only available for Enterprise and above
|
||||||
const channelGroupsEnabled = isLicensed && (license.SkuShortName === LicenseSkus.Enterprise || license.SkuShortName === LicenseSkus.E20);
|
const channelGroupsEnabled = isLicensed && isMinimumEnterpriseLicense(license);
|
||||||
|
|
||||||
const guestAccountsEnabled = config.EnableGuestAccounts === 'true';
|
const guestAccountsEnabled = config.EnableGuestAccounts === 'true';
|
||||||
const channelID = ownProps.match.params.channel_id;
|
const channelID = ownProps.match.params.channel_id;
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ import {runEaseOfUseChecks} from './dashboard_checks/easy_management';
|
|||||||
import {runPerformanceChecks} from './dashboard_checks/performance';
|
import {runPerformanceChecks} from './dashboard_checks/performance';
|
||||||
import {runUpdateChecks} from './dashboard_checks/updates';
|
import {runUpdateChecks} from './dashboard_checks/updates';
|
||||||
|
|
||||||
import {daysToLicenseExpire, isEnterpriseOrE20License, getIsStarterLicense} from '../../../utils/license_utils';
|
import {daysToLicenseExpire, getIsStarterLicense, isEnterpriseLicense} from '../../../utils/license_utils';
|
||||||
|
|
||||||
export const impactModifiers: Record<ItemStatus, number> = {
|
export const impactModifiers: Record<ItemStatus, number> = {
|
||||||
[ItemStatus.NONE]: 1,
|
[ItemStatus.NONE]: 1,
|
||||||
@@ -232,7 +232,7 @@ const useMetricsData = (
|
|||||||
const isLicensed = license?.IsLicensed === 'true' && daysUntilExpiration >= 0;
|
const isLicensed = license?.IsLicensed === 'true' && daysUntilExpiration >= 0;
|
||||||
|
|
||||||
const isCloud = license?.Cloud === 'true';
|
const isCloud = license?.Cloud === 'true';
|
||||||
const isEnterpriseLicense = isEnterpriseOrE20License(license);
|
const isEnterprise = isEnterpriseLicense(license);
|
||||||
const isStarterLicense = getIsStarterLicense(license);
|
const isStarterLicense = getIsStarterLicense(license);
|
||||||
|
|
||||||
const [, contactSalesLink] = useOpenSalesLink();
|
const [, contactSalesLink] = useOpenSalesLink();
|
||||||
@@ -244,13 +244,13 @@ const useMetricsData = (
|
|||||||
|
|
||||||
const options: Options = useMemo(() => ({
|
const options: Options = useMemo(() => ({
|
||||||
isLicensed,
|
isLicensed,
|
||||||
isEnterpriseLicense,
|
isEnterpriseLicense: isEnterprise,
|
||||||
trialOrEnterpriseCtaConfig,
|
trialOrEnterpriseCtaConfig,
|
||||||
isStarterLicense,
|
isStarterLicense,
|
||||||
isCloud,
|
isCloud,
|
||||||
analytics,
|
analytics,
|
||||||
installedVersion,
|
installedVersion,
|
||||||
}), [isLicensed, isEnterpriseLicense, trialOrEnterpriseCtaConfig, isStarterLicense, isCloud, analytics, installedVersion]);
|
}), [isLicensed, isEnterprise, trialOrEnterpriseCtaConfig, isStarterLicense, isCloud, analytics, installedVersion]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ describe('components/ConfigurationBar', () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
test('should match snapshot, expired, in grace period', () => {
|
test('should match snapshot, expired, in grace period', () => {
|
||||||
const props = {...baseProps, license: {Id: '1234', IsLicensed: 'true', ExpiresAt: Date.now() - millisPerDay}};
|
const props = {...baseProps, license: {Id: '1234', IsLicensed: 'true', ExpiresAt: Date.now() - millisPerDay, SkuShortName: 'enterprise'}};
|
||||||
const wrapper = shallowWithIntl(
|
const wrapper = shallowWithIntl(
|
||||||
<ConfigurationBar {...props}/>,
|
<ConfigurationBar {...props}/>,
|
||||||
);
|
);
|
||||||
@@ -43,7 +43,7 @@ describe('components/ConfigurationBar', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('should match snapshot, expired', () => {
|
test('should match snapshot, expired', () => {
|
||||||
const props = {...baseProps, license: {Id: '1234', IsLicensed: 'true', ExpiresAt: Date.now() - (11 * millisPerDay)}};
|
const props = {...baseProps, license: {Id: '1234', IsLicensed: 'true', ExpiresAt: Date.now() - (11 * millisPerDay), SkuShortName: 'enterprise'}};
|
||||||
const wrapper = shallowWithIntl(
|
const wrapper = shallowWithIntl(
|
||||||
<ConfigurationBar {...props}/>,
|
<ConfigurationBar {...props}/>,
|
||||||
);
|
);
|
||||||
@@ -52,7 +52,7 @@ describe('components/ConfigurationBar', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('should match snapshot, expired, regular user', () => {
|
test('should match snapshot, expired, regular user', () => {
|
||||||
const props = {...baseProps, canViewSystemErrors: false, license: {Id: '1234', IsLicensed: 'true', ExpiresAt: Date.now() - (11 * millisPerDay)}};
|
const props = {...baseProps, canViewSystemErrors: false, license: {Id: '1234', IsLicensed: 'true', ExpiresAt: Date.now() - (11 * millisPerDay), SkuShortName: 'enterprise'}};
|
||||||
const wrapper = shallowWithIntl(
|
const wrapper = shallowWithIntl(
|
||||||
<ConfigurationBar {...props}/>,
|
<ConfigurationBar {...props}/>,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import {getMySystemPermissions, haveISystemPermission} from 'mattermost-redux/se
|
|||||||
|
|
||||||
import AdminDefinition from 'components/admin_console/admin_definition';
|
import AdminDefinition from 'components/admin_console/admin_definition';
|
||||||
|
|
||||||
import {isEnterpriseOrE20License} from '../utils/license_utils';
|
import {isEnterpriseLicense} from '../utils/license_utils';
|
||||||
|
|
||||||
export const getAdminDefinition = createSelector(
|
export const getAdminDefinition = createSelector(
|
||||||
'getAdminDefinition',
|
'getAdminDefinition',
|
||||||
@@ -64,7 +64,7 @@ export const getShowManageUserSettings = createSelector(
|
|||||||
(license, state) => {
|
(license, state) => {
|
||||||
const hasWriteUserManagementPermission = haveISystemPermission(state, {permission: Permissions.SYSCONSOLE_WRITE_USERMANAGEMENT_USERS});
|
const hasWriteUserManagementPermission = haveISystemPermission(state, {permission: Permissions.SYSCONSOLE_WRITE_USERMANAGEMENT_USERS});
|
||||||
|
|
||||||
const isEnterprise = isEnterpriseOrE20License(license);
|
const isEnterprise = isEnterpriseLicense(license);
|
||||||
|
|
||||||
return hasWriteUserManagementPermission && isEnterprise;
|
return hasWriteUserManagementPermission && isEnterprise;
|
||||||
},
|
},
|
||||||
@@ -77,7 +77,7 @@ export const getShowLockedManageUserSettings = createSelector(
|
|||||||
(license, state) => {
|
(license, state) => {
|
||||||
const hasWriteUserManagementPermission = haveISystemPermission(state, {permission: Permissions.SYSCONSOLE_WRITE_USERMANAGEMENT_USERS});
|
const hasWriteUserManagementPermission = haveISystemPermission(state, {permission: Permissions.SYSCONSOLE_WRITE_USERMANAGEMENT_USERS});
|
||||||
|
|
||||||
const isEnterprise = isEnterpriseOrE20License(license);
|
const isEnterprise = isEnterpriseLicense(license);
|
||||||
|
|
||||||
return hasWriteUserManagementPermission && !isEnterprise;
|
return hasWriteUserManagementPermission && !isEnterprise;
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -539,6 +539,20 @@ export enum LicenseSkus {
|
|||||||
Starter = 'starter',
|
Starter = 'starter',
|
||||||
Professional = 'professional',
|
Professional = 'professional',
|
||||||
Enterprise = 'enterprise',
|
Enterprise = 'enterprise',
|
||||||
|
Premium = 'premium',
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getLicenseTier(licenseSku: string): number {
|
||||||
|
switch (licenseSku) {
|
||||||
|
case LicenseSkus.Professional:
|
||||||
|
return 10;
|
||||||
|
case LicenseSkus.Enterprise:
|
||||||
|
return 20;
|
||||||
|
case LicenseSkus.Premium:
|
||||||
|
return 30;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const CloudProductToSku = {
|
export const CloudProductToSku = {
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||||
// See LICENSE.txt for license information.
|
// See LICENSE.txt for license information.
|
||||||
|
|
||||||
import {LicenseSkus} from 'utils/constants';
|
import {isLicenseExpired, isLicenseExpiring, isLicensePastGracePeriod} from 'utils/license_utils';
|
||||||
import {isLicenseExpired, isLicenseExpiring, isLicensePastGracePeriod, isEnterpriseOrE20License} from 'utils/license_utils';
|
|
||||||
|
|
||||||
describe('license_utils', () => {
|
describe('license_utils', () => {
|
||||||
const millisPerDay = 24 * 60 * 60 * 1000;
|
const millisPerDay = 24 * 60 * 60 * 1000;
|
||||||
@@ -46,24 +45,4 @@ describe('license_utils', () => {
|
|||||||
expect(isLicensePastGracePeriod(license)).toBeTruthy();
|
expect(isLicensePastGracePeriod(license)).toBeTruthy();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('isEnterpriseOrE20License', () => {
|
|
||||||
it('should return False if not Enterprise or E20', () => {
|
|
||||||
const license = {Id: '1234', IsLicensed: 'true', Cloud: 'false', SkuShortName: LicenseSkus.Starter};
|
|
||||||
|
|
||||||
expect(isEnterpriseOrE20License(license)).toBeFalsy();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return True if Enterprise', () => {
|
|
||||||
const license = {Id: '1234', IsLicensed: 'true', Cloud: 'false', SkuShortName: LicenseSkus.Enterprise};
|
|
||||||
|
|
||||||
expect(isEnterpriseOrE20License(license)).toBeTruthy();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return True if E20', () => {
|
|
||||||
const license = {Id: '1234', IsLicensed: 'true', Cloud: 'false', SkuShortName: LicenseSkus.E20};
|
|
||||||
|
|
||||||
expect(isEnterpriseOrE20License(license)).toBeTruthy();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import moment from 'moment';
|
|||||||
import type {Product} from '@mattermost/types/cloud';
|
import type {Product} from '@mattermost/types/cloud';
|
||||||
import type {ClientLicense} from '@mattermost/types/config';
|
import type {ClientLicense} from '@mattermost/types/config';
|
||||||
|
|
||||||
import {CloudProducts, LicenseSkus, SelfHostedProducts} from 'utils/constants';
|
import {CloudProducts, getLicenseTier, LicenseSkus, SelfHostedProducts} from 'utils/constants';
|
||||||
|
|
||||||
const LICENSE_EXPIRY_NOTIFICATION = 1000 * 60 * 60 * 24 * 60; // 60 days
|
const LICENSE_EXPIRY_NOTIFICATION = 1000 * 60 * 60 * 24 * 60; // 60 days
|
||||||
const LICENSE_GRACE_PERIOD = 1000 * 60 * 60 * 24 * 10; // 10 days
|
const LICENSE_GRACE_PERIOD = 1000 * 60 * 60 * 24 * 10; // 10 days
|
||||||
@@ -84,14 +84,11 @@ export function getIsGovSku(license: ClientLicense) {
|
|||||||
return license?.IsGovSku === 'true';
|
return license?.IsGovSku === 'true';
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isEnterpriseOrE20License(license: ClientLicense) {
|
|
||||||
return license?.SkuShortName === LicenseSkus.Enterprise || license?.SkuShortName === LicenseSkus.E20;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const isEnterpriseLicense = (license?: ClientLicense) => {
|
export const isEnterpriseLicense = (license?: ClientLicense) => {
|
||||||
switch (license?.SkuShortName) {
|
switch (license?.SkuShortName) {
|
||||||
case LicenseSkus.Enterprise:
|
case LicenseSkus.Enterprise:
|
||||||
case LicenseSkus.E20:
|
case LicenseSkus.E20:
|
||||||
|
case LicenseSkus.Premium:
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -115,3 +112,19 @@ export function isEnterpriseOrCloudOrSKUStarterFree(license: ClientLicense, subs
|
|||||||
|
|
||||||
return isCloudStarterFree || isSelfHostedStarter || isStarterSKULicense;
|
return isCloudStarterFree || isSelfHostedStarter || isStarterSKULicense;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function isMinimumProfessionalLicense(license: ClientLicense): boolean {
|
||||||
|
if (!license) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return getLicenseTier(license.SkuShortName) >= getLicenseTier(LicenseSkus.Professional);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isMinimumEnterpriseLicense(license: ClientLicense): boolean {
|
||||||
|
if (!license) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return getLicenseTier(license.SkuShortName) >= getLicenseTier(LicenseSkus.Enterprise);
|
||||||
|
}
|
||||||
|
|||||||
@@ -18,9 +18,12 @@ export const getSkuDisplayName = (skuShortName: string, isGovSku: boolean): stri
|
|||||||
case LicenseSkus.Starter:
|
case LicenseSkus.Starter:
|
||||||
skuName = 'Starter';
|
skuName = 'Starter';
|
||||||
break;
|
break;
|
||||||
default:
|
case LicenseSkus.Enterprise:
|
||||||
skuName = 'Enterprise';
|
skuName = 'Enterprise';
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
skuName = 'Premium';
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
skuName += isGovSku ? ' Gov' : '';
|
skuName += isGovSku ? ' Gov' : '';
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user