PLT-7622 Improvements to server handling of webapp plugins (#7445)
* Improvements to server handling of webapp plugins * Fix newline * Update manifest function names
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
2a6cd44f23
Коммит
2628022275
@@ -25,6 +25,8 @@ func InitPlugin() {
|
|||||||
BaseRoutes.Plugins.Handle("", ApiSessionRequired(getPlugins)).Methods("GET")
|
BaseRoutes.Plugins.Handle("", ApiSessionRequired(getPlugins)).Methods("GET")
|
||||||
BaseRoutes.Plugin.Handle("", ApiSessionRequired(removePlugin)).Methods("DELETE")
|
BaseRoutes.Plugin.Handle("", ApiSessionRequired(removePlugin)).Methods("DELETE")
|
||||||
|
|
||||||
|
BaseRoutes.Plugins.Handle("/webapp", ApiHandler(getWebappPlugins)).Methods("GET")
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func uploadPlugin(c *Context, w http.ResponseWriter, r *http.Request) {
|
func uploadPlugin(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||||
@@ -118,3 +120,25 @@ func removePlugin(c *Context, w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
ReturnStatusOK(w)
|
ReturnStatusOK(w)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getWebappPlugins(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||||
|
if !*utils.Cfg.PluginSettings.Enable {
|
||||||
|
c.Err = model.NewAppError("getWebappPlugins", "app.plugin.disabled.app_error", nil, "", http.StatusNotImplemented)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
manifests, err := c.App.GetActivePluginManifests()
|
||||||
|
if err != nil {
|
||||||
|
c.Err = err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
clientManifests := []*model.Manifest{}
|
||||||
|
for _, m := range manifests {
|
||||||
|
if m.HasClient() {
|
||||||
|
clientManifests = append(clientManifests, m.ClientManifest())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
w.Write([]byte(model.ManifestListToJson(clientManifests)))
|
||||||
|
}
|
||||||
|
|||||||
@@ -17,14 +17,11 @@ import (
|
|||||||
func TestPlugin(t *testing.T) {
|
func TestPlugin(t *testing.T) {
|
||||||
pluginDir, err := ioutil.TempDir("", "mm-plugin-test")
|
pluginDir, err := ioutil.TempDir("", "mm-plugin-test")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
defer func() {
|
defer os.RemoveAll(pluginDir)
|
||||||
os.RemoveAll(pluginDir)
|
|
||||||
}()
|
|
||||||
webappDir, err := ioutil.TempDir("", "mm-webapp-test")
|
webappDir, err := ioutil.TempDir("", "mm-webapp-test")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
defer func() {
|
defer os.RemoveAll(webappDir)
|
||||||
os.RemoveAll(webappDir)
|
|
||||||
}()
|
|
||||||
|
|
||||||
th := SetupEnterprise().InitBasic().InitSystemAdmin()
|
th := SetupEnterprise().InitBasic().InitSystemAdmin()
|
||||||
defer TearDown()
|
defer TearDown()
|
||||||
@@ -50,9 +47,7 @@ func TestPlugin(t *testing.T) {
|
|||||||
|
|
||||||
// Successful upload
|
// Successful upload
|
||||||
manifest, resp := th.SystemAdminClient.UploadPlugin(file)
|
manifest, resp := th.SystemAdminClient.UploadPlugin(file)
|
||||||
defer func() {
|
defer os.RemoveAll("plugins/testplugin")
|
||||||
os.RemoveAll("plugins/testplugin")
|
|
||||||
}()
|
|
||||||
CheckNoError(t, resp)
|
CheckNoError(t, resp)
|
||||||
|
|
||||||
assert.Equal(t, "testplugin", manifest.Id)
|
assert.Equal(t, "testplugin", manifest.Id)
|
||||||
@@ -91,6 +86,19 @@ func TestPlugin(t *testing.T) {
|
|||||||
_, resp = th.Client.GetPlugins()
|
_, resp = th.Client.GetPlugins()
|
||||||
CheckForbiddenStatus(t, resp)
|
CheckForbiddenStatus(t, resp)
|
||||||
|
|
||||||
|
// Successful webapp get
|
||||||
|
manifests, resp = th.Client.GetWebappPlugins()
|
||||||
|
CheckNoError(t, resp)
|
||||||
|
|
||||||
|
found = false
|
||||||
|
for _, m := range manifests {
|
||||||
|
if m.Id == manifest.Id {
|
||||||
|
found = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.True(t, found)
|
||||||
|
|
||||||
// Successful remove
|
// Successful remove
|
||||||
ok, resp := th.SystemAdminClient.RemovePlugin(manifest.Id)
|
ok, resp := th.SystemAdminClient.RemovePlugin(manifest.Id)
|
||||||
CheckNoError(t, resp)
|
CheckNoError(t, resp)
|
||||||
|
|||||||
@@ -244,7 +244,6 @@ func getClientConfig(c *Context, w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
respCfg["NoAccounts"] = strconv.FormatBool(c.App.IsFirstUserAccount())
|
respCfg["NoAccounts"] = strconv.FormatBool(c.App.IsFirstUserAccount())
|
||||||
respCfg["Plugins"] = c.App.GetPluginsForClientConfig()
|
|
||||||
|
|
||||||
w.Write([]byte(model.MapToJson(respCfg)))
|
w.Write([]byte(model.MapToJson(respCfg)))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -252,6 +252,12 @@ func (a *App) UnpackAndActivatePlugin(pluginFile io.Reader) (*model.Manifest, *m
|
|||||||
return nil, model.NewAppError("UnpackAndActivatePlugin", "app.plugin.activate.app_error", nil, err.Error(), http.StatusBadRequest)
|
return nil, model.NewAppError("UnpackAndActivatePlugin", "app.plugin.activate.app_error", nil, err.Error(), http.StatusBadRequest)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if manifest.HasClient() {
|
||||||
|
message := model.NewWebSocketEvent(model.WEBSOCKET_EVENT_PLUGIN_ACTIVATED, "", "", "", nil)
|
||||||
|
message.Add("manifest", manifest.ClientManifest())
|
||||||
|
Publish(message)
|
||||||
|
}
|
||||||
|
|
||||||
return manifest, nil
|
return manifest, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -260,10 +266,7 @@ func (a *App) GetActivePluginManifests() ([]*model.Manifest, *model.AppError) {
|
|||||||
return nil, model.NewAppError("GetActivePluginManifests", "app.plugin.disabled.app_error", nil, "", http.StatusNotImplemented)
|
return nil, model.NewAppError("GetActivePluginManifests", "app.plugin.disabled.app_error", nil, "", http.StatusNotImplemented)
|
||||||
}
|
}
|
||||||
|
|
||||||
plugins, err := a.PluginEnv.ActivePlugins()
|
plugins := a.PluginEnv.ActivePlugins()
|
||||||
if err != nil {
|
|
||||||
return nil, model.NewAppError("GetActivePluginManifests", "app.plugin.get_plugins.app_error", nil, err.Error(), http.StatusInternalServerError)
|
|
||||||
}
|
|
||||||
|
|
||||||
manifests := make([]*model.Manifest, len(plugins))
|
manifests := make([]*model.Manifest, len(plugins))
|
||||||
for i, plugin := range plugins {
|
for i, plugin := range plugins {
|
||||||
@@ -278,6 +281,15 @@ func (a *App) RemovePlugin(id string) *model.AppError {
|
|||||||
return model.NewAppError("RemovePlugin", "app.plugin.disabled.app_error", nil, "", http.StatusNotImplemented)
|
return model.NewAppError("RemovePlugin", "app.plugin.disabled.app_error", nil, "", http.StatusNotImplemented)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
plugins := a.PluginEnv.ActivePlugins()
|
||||||
|
manifest := &model.Manifest{}
|
||||||
|
for _, p := range plugins {
|
||||||
|
if p.Manifest.Id == id {
|
||||||
|
manifest = p.Manifest
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
err := a.PluginEnv.DeactivatePlugin(id)
|
err := a.PluginEnv.DeactivatePlugin(id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return model.NewAppError("RemovePlugin", "app.plugin.deactivate.app_error", nil, err.Error(), http.StatusBadRequest)
|
return model.NewAppError("RemovePlugin", "app.plugin.deactivate.app_error", nil, err.Error(), http.StatusBadRequest)
|
||||||
@@ -288,41 +300,15 @@ func (a *App) RemovePlugin(id string) *model.AppError {
|
|||||||
return model.NewAppError("RemovePlugin", "app.plugin.remove.app_error", nil, err.Error(), http.StatusInternalServerError)
|
return model.NewAppError("RemovePlugin", "app.plugin.remove.app_error", nil, err.Error(), http.StatusInternalServerError)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if manifest.HasClient() {
|
||||||
|
message := model.NewWebSocketEvent(model.WEBSOCKET_EVENT_PLUGIN_DEACTIVATED, "", "", "", nil)
|
||||||
|
message.Add("manifest", manifest.ClientManifest())
|
||||||
|
Publish(message)
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Temporary WIP function/type for experimental webapp plugins
|
|
||||||
type ClientConfigPlugin struct {
|
|
||||||
Id string `json:"id"`
|
|
||||||
BundlePath string `json:"bundle_path"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *App) GetPluginsForClientConfig() string {
|
|
||||||
if a.PluginEnv == nil || !*utils.Cfg.PluginSettings.Enable {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
plugins, err := a.PluginEnv.ActivePlugins()
|
|
||||||
if err != nil {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
pluginsConfig := []ClientConfigPlugin{}
|
|
||||||
for _, plugin := range plugins {
|
|
||||||
if plugin.Manifest.Webapp == nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
pluginsConfig = append(pluginsConfig, ClientConfigPlugin{Id: plugin.Manifest.Id, BundlePath: plugin.Manifest.Webapp.BundlePath})
|
|
||||||
}
|
|
||||||
|
|
||||||
b, err := json.Marshal(pluginsConfig)
|
|
||||||
if err != nil {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
return string(b)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *App) InitPlugins(pluginPath, webappPath string) {
|
func (a *App) InitPlugins(pluginPath, webappPath string) {
|
||||||
a.InitBuiltInPlugins()
|
a.InitBuiltInPlugins()
|
||||||
|
|
||||||
@@ -338,6 +324,12 @@ func (a *App) InitPlugins(pluginPath, webappPath string) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = os.Mkdir(webappPath, 0744)
|
||||||
|
if err != nil && !os.IsExist(err) {
|
||||||
|
l4g.Error("failed to start up plugins: " + err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
a.PluginEnv, err = pluginenv.New(
|
a.PluginEnv, err = pluginenv.New(
|
||||||
pluginenv.SearchPath(pluginPath),
|
pluginenv.SearchPath(pluginPath),
|
||||||
pluginenv.WebappPath(webappPath),
|
pluginenv.WebappPath(webappPath),
|
||||||
|
|||||||
@@ -62,11 +62,6 @@ func runServer(configFileLocation string) {
|
|||||||
l4g.Info(utils.T("mattermost.working_dir"), pwd)
|
l4g.Info(utils.T("mattermost.working_dir"), pwd)
|
||||||
l4g.Info(utils.T("mattermost.config_file"), utils.FindConfigFile(configFileLocation))
|
l4g.Info(utils.T("mattermost.config_file"), utils.FindConfigFile(configFileLocation))
|
||||||
|
|
||||||
// Enable developer settings if this is a "dev" build
|
|
||||||
if model.BuildNumber == "dev" {
|
|
||||||
*utils.Cfg.ServiceSettings.EnableDeveloper = true
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := utils.TestFileConnection(); err != nil {
|
if err := utils.TestFileConnection(); err != nil {
|
||||||
l4g.Error("Problem with file storage settings: " + err.Error())
|
l4g.Error("Problem with file storage settings: " + err.Error())
|
||||||
}
|
}
|
||||||
@@ -79,7 +74,12 @@ func runServer(configFileLocation string) {
|
|||||||
if model.BuildEnterpriseReady == "true" {
|
if model.BuildEnterpriseReady == "true" {
|
||||||
a.LoadLicense()
|
a.LoadLicense()
|
||||||
}
|
}
|
||||||
a.InitPlugins("plugins", "webapp/dist")
|
|
||||||
|
if webappDir, ok := utils.FindDir(model.CLIENT_DIR); ok {
|
||||||
|
a.InitPlugins("plugins", webappDir+"/plugins")
|
||||||
|
} else {
|
||||||
|
l4g.Error("Unable to find webapp directory, could not initialize plugins")
|
||||||
|
}
|
||||||
|
|
||||||
wsapi.InitRouter()
|
wsapi.InitRouter()
|
||||||
api4.InitApi(a.Srv.Router, false)
|
api4.InitApi(a.Srv.Router, false)
|
||||||
@@ -98,6 +98,11 @@ func runServer(configFileLocation string) {
|
|||||||
|
|
||||||
app.ReloadConfig()
|
app.ReloadConfig()
|
||||||
|
|
||||||
|
// Enable developer settings if this is a "dev" build
|
||||||
|
if model.BuildNumber == "dev" {
|
||||||
|
*utils.Cfg.ServiceSettings.EnableDeveloper = true
|
||||||
|
}
|
||||||
|
|
||||||
resetStatuses(a)
|
resetStatuses(a)
|
||||||
|
|
||||||
a.StartServer()
|
a.StartServer()
|
||||||
|
|||||||
@@ -3088,3 +3088,14 @@ func (c *Client4) RemovePlugin(id string) (bool, *Response) {
|
|||||||
return CheckStatusOK(r), BuildResponse(r)
|
return CheckStatusOK(r), BuildResponse(r)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetWebappPlugins will return a list of plugins that the webapp should download.
|
||||||
|
// WARNING: PLUGINS ARE STILL EXPERIMENTAL. THIS FUNCTION IS SUBJECT TO CHANGE.
|
||||||
|
func (c *Client4) GetWebappPlugins() ([]*Manifest, *Response) {
|
||||||
|
if r, err := c.DoApiGet(c.GetPluginsRoute()+"/webapp", ""); err != nil {
|
||||||
|
return nil, BuildErrorResponse(r, err)
|
||||||
|
} else {
|
||||||
|
defer closeBody(r)
|
||||||
|
return ManifestListFromJson(r.Body), BuildResponse(r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -12,8 +12,9 @@ import (
|
|||||||
|
|
||||||
type Manifest struct {
|
type Manifest struct {
|
||||||
Id string `json:"id" yaml:"id"`
|
Id string `json:"id" yaml:"id"`
|
||||||
Name string `json:"name" yaml:"name"`
|
Name string `json:"name,omitempty" yaml:"name,omitempty"`
|
||||||
Description string `json:"description" yaml:"description"`
|
Description string `json:"description,omitempty" yaml:"description,omitempty"`
|
||||||
|
Version string `json:"version" yaml:"version"`
|
||||||
Backend *ManifestBackend `json:"backend,omitempty" yaml:"backend,omitempty"`
|
Backend *ManifestBackend `json:"backend,omitempty" yaml:"backend,omitempty"`
|
||||||
Webapp *ManifestWebapp `json:"webapp,omitempty" yaml:"webapp,omitempty"`
|
Webapp *ManifestWebapp `json:"webapp,omitempty" yaml:"webapp,omitempty"`
|
||||||
}
|
}
|
||||||
@@ -66,6 +67,19 @@ func ManifestListFromJson(data io.Reader) []*Manifest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *Manifest) HasClient() bool {
|
||||||
|
return m.Webapp != nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Manifest) ClientManifest() *Manifest {
|
||||||
|
cm := new(Manifest)
|
||||||
|
*cm = *m
|
||||||
|
cm.Name = ""
|
||||||
|
cm.Description = ""
|
||||||
|
cm.Backend = nil
|
||||||
|
return cm
|
||||||
|
}
|
||||||
|
|
||||||
// FindManifest will find and parse the manifest in a given directory.
|
// FindManifest will find and parse the manifest in a given directory.
|
||||||
//
|
//
|
||||||
// In all cases other than a does-not-exist error, path is set to the path of the manifest file that was
|
// In all cases other than a does-not-exist error, path is set to the path of the manifest file that was
|
||||||
|
|||||||
@@ -129,3 +129,51 @@ func TestManifestJson(t *testing.T) {
|
|||||||
assert.Equal(t, newManifestList, manifestList)
|
assert.Equal(t, newManifestList, manifestList)
|
||||||
assert.Equal(t, ManifestListToJson(newManifestList), json)
|
assert.Equal(t, ManifestListToJson(newManifestList), json)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestManifestHasClient(t *testing.T) {
|
||||||
|
manifest := &Manifest{
|
||||||
|
Id: "theid",
|
||||||
|
Backend: &ManifestBackend{
|
||||||
|
Executable: "theexecutable",
|
||||||
|
},
|
||||||
|
Webapp: &ManifestWebapp{
|
||||||
|
BundlePath: "thebundlepath",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.True(t, manifest.HasClient())
|
||||||
|
|
||||||
|
manifest.Webapp = nil
|
||||||
|
assert.False(t, manifest.HasClient())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestManifestClientManifest(t *testing.T) {
|
||||||
|
manifest := &Manifest{
|
||||||
|
Id: "theid",
|
||||||
|
Name: "thename",
|
||||||
|
Description: "thedescription",
|
||||||
|
Version: "0.0.1",
|
||||||
|
Backend: &ManifestBackend{
|
||||||
|
Executable: "theexecutable",
|
||||||
|
},
|
||||||
|
Webapp: &ManifestWebapp{
|
||||||
|
BundlePath: "thebundlepath",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
sanitized := manifest.ClientManifest()
|
||||||
|
|
||||||
|
assert.NotEmpty(t, sanitized.Id)
|
||||||
|
assert.NotEmpty(t, sanitized.Version)
|
||||||
|
assert.NotEmpty(t, sanitized.Webapp)
|
||||||
|
assert.Empty(t, sanitized.Name)
|
||||||
|
assert.Empty(t, sanitized.Description)
|
||||||
|
assert.Empty(t, sanitized.Backend)
|
||||||
|
|
||||||
|
assert.NotEmpty(t, manifest.Id)
|
||||||
|
assert.NotEmpty(t, manifest.Version)
|
||||||
|
assert.NotEmpty(t, manifest.Webapp)
|
||||||
|
assert.NotEmpty(t, manifest.Name)
|
||||||
|
assert.NotEmpty(t, manifest.Description)
|
||||||
|
assert.NotEmpty(t, manifest.Backend)
|
||||||
|
}
|
||||||
|
|||||||
@@ -39,6 +39,8 @@ const (
|
|||||||
WEBSOCKET_EVENT_RESPONSE = "response"
|
WEBSOCKET_EVENT_RESPONSE = "response"
|
||||||
WEBSOCKET_EVENT_EMOJI_ADDED = "emoji_added"
|
WEBSOCKET_EVENT_EMOJI_ADDED = "emoji_added"
|
||||||
WEBSOCKET_EVENT_CHANNEL_VIEWED = "channel_viewed"
|
WEBSOCKET_EVENT_CHANNEL_VIEWED = "channel_viewed"
|
||||||
|
WEBSOCKET_EVENT_PLUGIN_ACTIVATED = "plugin_activated" // EXPERIMENTAL - SUBJECT TO CHANGE
|
||||||
|
WEBSOCKET_EVENT_PLUGIN_DEACTIVATED = "plugin_deactivated" // EXPERIMENTAL - SUBJECT TO CHANGE
|
||||||
)
|
)
|
||||||
|
|
||||||
type WebSocketMessage interface {
|
type WebSocketMessage interface {
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ func (env *Environment) Plugins() ([]*model.BundleInfo, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Returns a list of all currently active plugins within the environment.
|
// Returns a list of all currently active plugins within the environment.
|
||||||
func (env *Environment) ActivePlugins() ([]*model.BundleInfo, error) {
|
func (env *Environment) ActivePlugins() []*model.BundleInfo {
|
||||||
env.mutex.RLock()
|
env.mutex.RLock()
|
||||||
defer env.mutex.RUnlock()
|
defer env.mutex.RUnlock()
|
||||||
|
|
||||||
@@ -75,7 +75,7 @@ func (env *Environment) ActivePlugins() ([]*model.BundleInfo, error) {
|
|||||||
activePlugins = append(activePlugins, p.BundleInfo)
|
activePlugins = append(activePlugins, p.BundleInfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
return activePlugins, nil
|
return activePlugins
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the ids of the currently active plugins.
|
// Returns the ids of the currently active plugins.
|
||||||
|
|||||||
@@ -127,8 +127,7 @@ func TestEnvironment(t *testing.T) {
|
|||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Len(t, plugins, 3)
|
assert.Len(t, plugins, 3)
|
||||||
|
|
||||||
activePlugins, err := env.ActivePlugins()
|
activePlugins := env.ActivePlugins()
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.Len(t, activePlugins, 0)
|
assert.Len(t, activePlugins, 0)
|
||||||
|
|
||||||
assert.Error(t, env.ActivatePlugin("x"))
|
assert.Error(t, env.ActivatePlugin("x"))
|
||||||
@@ -150,8 +149,7 @@ func TestEnvironment(t *testing.T) {
|
|||||||
|
|
||||||
assert.NoError(t, env.ActivatePlugin("foo"))
|
assert.NoError(t, env.ActivatePlugin("foo"))
|
||||||
assert.Equal(t, env.ActivePluginIds(), []string{"foo"})
|
assert.Equal(t, env.ActivePluginIds(), []string{"foo"})
|
||||||
activePlugins, err = env.ActivePlugins()
|
activePlugins = env.ActivePlugins()
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.Len(t, activePlugins, 1)
|
assert.Len(t, activePlugins, 1)
|
||||||
assert.Error(t, env.ActivatePlugin("foo"))
|
assert.Error(t, env.ActivatePlugin("foo"))
|
||||||
|
|
||||||
|
|||||||
26
web/web.go
26
web/web.go
@@ -26,12 +26,17 @@ func InitWeb() {
|
|||||||
if *utils.Cfg.ServiceSettings.WebserverMode != "disabled" {
|
if *utils.Cfg.ServiceSettings.WebserverMode != "disabled" {
|
||||||
staticDir, _ := utils.FindDir(model.CLIENT_DIR)
|
staticDir, _ := utils.FindDir(model.CLIENT_DIR)
|
||||||
l4g.Debug("Using client directory at %v", staticDir)
|
l4g.Debug("Using client directory at %v", staticDir)
|
||||||
|
|
||||||
|
staticHandler := staticHandler(http.StripPrefix("/static/", http.FileServer(http.Dir(staticDir))))
|
||||||
|
pluginHandler := pluginHandler(http.StripPrefix("/static/plugins/", http.FileServer(http.Dir(staticDir+"plugins/"))))
|
||||||
|
|
||||||
if *utils.Cfg.ServiceSettings.WebserverMode == "gzip" {
|
if *utils.Cfg.ServiceSettings.WebserverMode == "gzip" {
|
||||||
mainrouter.PathPrefix("/static/").Handler(gziphandler.GzipHandler(staticHandler(http.StripPrefix("/static/", http.FileServer(http.Dir(staticDir))))))
|
staticHandler = gziphandler.GzipHandler(staticHandler)
|
||||||
} else {
|
pluginHandler = gziphandler.GzipHandler(pluginHandler)
|
||||||
mainrouter.PathPrefix("/static/").Handler(staticHandler(http.StripPrefix("/static/", http.FileServer(http.Dir(staticDir)))))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mainrouter.PathPrefix("/static/plugins/").Handler(pluginHandler)
|
||||||
|
mainrouter.PathPrefix("/static/").Handler(staticHandler)
|
||||||
mainrouter.Handle("/{anything:.*}", api.AppHandlerIndependent(root)).Methods("GET")
|
mainrouter.Handle("/{anything:.*}", api.AppHandlerIndependent(root)).Methods("GET")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -47,6 +52,21 @@ func staticHandler(handler http.Handler) http.Handler {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func pluginHandler(handler http.Handler) http.Handler {
|
||||||
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if *utils.Cfg.ServiceSettings.EnableDeveloper {
|
||||||
|
w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate")
|
||||||
|
} else {
|
||||||
|
w.Header().Set("Cache-Control", "max-age=31556926, public")
|
||||||
|
}
|
||||||
|
if strings.HasSuffix(r.URL.Path, "/") {
|
||||||
|
http.NotFound(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
handler.ServeHTTP(w, r)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
//map should be of minimum required browser version.
|
//map should be of minimum required browser version.
|
||||||
//var browsersNotSupported string = "MSIE/11;Internet Explorer/11;Safari/9;Chrome/43;Edge/15;Firefox/52"
|
//var browsersNotSupported string = "MSIE/11;Internet Explorer/11;Safari/9;Chrome/43;Edge/15;Firefox/52"
|
||||||
//var browserMinimumSupported = [6]string{"MSIE/11", "Internet Explorer/11", "Safari/9", "Chrome/43", "Edge/15", "Firefox/52"}
|
//var browserMinimumSupported = [6]string{"MSIE/11", "Internet Explorer/11", "Safari/9", "Chrome/43", "Edge/15", "Firefox/52"}
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user