diff --git a/api4/config.go b/api4/config.go index 91e62862a4..a1f4bb3243 100644 --- a/api4/config.go +++ b/api4/config.go @@ -156,6 +156,11 @@ func updateConfig(c *Context, w http.ResponseWriter, r *http.Request) { *cfg.PluginSettings.MarketplaceURL = *appCfg.PluginSettings.MarketplaceURL } + if cfg.PluginSettings.PluginStates[model.PluginIdFocalboard].Enable && cfg.FeatureFlags.BoardsProduct { + c.Err = model.NewAppError("EnablePlugin", "app.plugin.product_mode.app_error", map[string]any{"Name": model.PluginIdFocalboard}, "", http.StatusInternalServerError) + return + } + if appErr := c.App.CheckFreemiumLimitsForConfigSave(appCfg, cfg); appErr != nil { c.Err = appErr return diff --git a/app/plugin.go b/app/plugin.go index 50b750f11c..b8c1898999 100644 --- a/app/plugin.go +++ b/app/plugin.go @@ -130,6 +130,23 @@ func (ch *Channels) syncPluginsActiveState() { } if pluginEnabled { + // Disable focalboard in product mode. + if pluginID == model.PluginIdFocalboard && ch.cfgSvc.Config().FeatureFlags.BoardsProduct { + msg := "Plugin cannot run in product mode. Disabling." + mlog.Warn(msg, mlog.String("plugin_id", model.PluginIdFocalboard)) + + // This is a mini-version of ch.disablePlugin. + // We don't call that directly, because that will recursively call + // this method. + ch.cfgSvc.UpdateConfig(func(cfg *model.Config) { + cfg.PluginSettings.PluginStates[pluginID] = &model.PluginState{Enable: false} + }) + pluginsEnvironment.SetPluginError(pluginID, msg) + ch.unregisterPluginCommands(pluginID) + disabledPlugins = append(disabledPlugins, plugin) + continue + } + enabledPlugins = append(enabledPlugins, plugin) } else { disabledPlugins = append(disabledPlugins, plugin) @@ -438,6 +455,10 @@ func (ch *Channels) enablePlugin(id string) *model.AppError { return model.NewAppError("EnablePlugin", "app.plugin.not_installed.app_error", nil, "", http.StatusNotFound) } + if id == model.PluginIdFocalboard && ch.cfgSvc.Config().FeatureFlags.BoardsProduct { + return model.NewAppError("EnablePlugin", "app.plugin.product_mode.app_error", map[string]any{"Name": model.PluginIdFocalboard}, "", http.StatusInternalServerError) + } + ch.cfgSvc.UpdateConfig(func(cfg *model.Config) { cfg.PluginSettings.PluginStates[id] = &model.PluginState{Enable: true} }) diff --git a/i18n/en.json b/i18n/en.json index 539746b078..5ebcc304a4 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -5915,6 +5915,10 @@ "id": "app.plugin.not_installed.app_error", "translation": "Plugin is not installed." }, + { + "id": "app.plugin.product_mode.app_error", + "translation": "Plugin {{.Name}} cannot be enabled in product mode." + }, { "id": "app.plugin.remove.app_error", "translation": "Unable to delete plugin." diff --git a/plugin/environment.go b/plugin/environment.go index 9226a2e878..fa737f5ecf 100644 --- a/plugin/environment.go +++ b/plugin/environment.go @@ -137,7 +137,7 @@ func (env *Environment) IsActive(id string) bool { return env.GetPluginState(id) == model.PluginStateRunning } -func (env *Environment) setPluginError(id string, err string) { +func (env *Environment) SetPluginError(id string, err string) { if rp, ok := env.registeredPlugins.Load(id); ok { p := rp.(registeredPlugin) p.Error = err @@ -233,9 +233,9 @@ func (env *Environment) GetManifest(pluginId string) (*model.Manifest, error) { func (env *Environment) Activate(id string) (manifest *model.Manifest, activated bool, reterr error) { defer func() { if reterr != nil { - env.setPluginError(id, reterr.Error()) + env.SetPluginError(id, reterr.Error()) } else { - env.setPluginError(id, "") + env.SetPluginError(id, "") } }()