github.com/nhannv/mattermost-server@v5.11.1+incompatible/app/plugin_install.go (about)

     1  // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
     2  // See LICENSE.txt for license information.
     3  
     4  package app
     5  
     6  import (
     7  	"io"
     8  	"io/ioutil"
     9  	"net/http"
    10  	"os"
    11  	"path/filepath"
    12  
    13  	"github.com/mattermost/mattermost-server/mlog"
    14  	"github.com/mattermost/mattermost-server/model"
    15  	"github.com/mattermost/mattermost-server/plugin"
    16  	"github.com/mattermost/mattermost-server/utils"
    17  )
    18  
    19  // InstallPlugin unpacks and installs a plugin but does not enable or activate it.
    20  func (a *App) InstallPlugin(pluginFile io.Reader, replace bool) (*model.Manifest, *model.AppError) {
    21  	return a.installPlugin(pluginFile, replace)
    22  }
    23  
    24  func (a *App) installPlugin(pluginFile io.Reader, replace bool) (*model.Manifest, *model.AppError) {
    25  	pluginsEnvironment := a.GetPluginsEnvironment()
    26  	if pluginsEnvironment == nil {
    27  		return nil, model.NewAppError("installPlugin", "app.plugin.disabled.app_error", nil, "", http.StatusNotImplemented)
    28  	}
    29  
    30  	tmpDir, err := ioutil.TempDir("", "plugintmp")
    31  	if err != nil {
    32  		return nil, model.NewAppError("installPlugin", "app.plugin.filesystem.app_error", nil, err.Error(), http.StatusInternalServerError)
    33  	}
    34  	defer os.RemoveAll(tmpDir)
    35  
    36  	if err = utils.ExtractTarGz(pluginFile, tmpDir); err != nil {
    37  		return nil, model.NewAppError("installPlugin", "app.plugin.extract.app_error", nil, err.Error(), http.StatusBadRequest)
    38  	}
    39  
    40  	tmpPluginDir := tmpDir
    41  	dir, err := ioutil.ReadDir(tmpDir)
    42  	if err != nil {
    43  		return nil, model.NewAppError("installPlugin", "app.plugin.filesystem.app_error", nil, err.Error(), http.StatusInternalServerError)
    44  	}
    45  
    46  	if len(dir) == 1 && dir[0].IsDir() {
    47  		tmpPluginDir = filepath.Join(tmpPluginDir, dir[0].Name())
    48  	}
    49  
    50  	manifest, _, err := model.FindManifest(tmpPluginDir)
    51  	if err != nil {
    52  		return nil, model.NewAppError("installPlugin", "app.plugin.manifest.app_error", nil, err.Error(), http.StatusBadRequest)
    53  	}
    54  
    55  	if !plugin.IsValidId(manifest.Id) {
    56  		return nil, model.NewAppError("installPlugin", "app.plugin.invalid_id.app_error", map[string]interface{}{"Min": plugin.MinIdLength, "Max": plugin.MaxIdLength, "Regex": plugin.ValidIdRegex}, "", http.StatusBadRequest)
    57  	}
    58  
    59  	// Stash the previous state of the plugin, if available
    60  	stashed := a.Config().PluginSettings.PluginStates[manifest.Id]
    61  
    62  	bundles, err := pluginsEnvironment.Available()
    63  	if err != nil {
    64  		return nil, model.NewAppError("installPlugin", "app.plugin.install.app_error", nil, err.Error(), http.StatusInternalServerError)
    65  	}
    66  
    67  	// Check that there is no plugin with the same ID
    68  	for _, bundle := range bundles {
    69  		if bundle.Manifest != nil && bundle.Manifest.Id == manifest.Id {
    70  			if !replace {
    71  				return nil, model.NewAppError("installPlugin", "app.plugin.install_id.app_error", nil, "", http.StatusBadRequest)
    72  			}
    73  
    74  			if err := a.RemovePlugin(manifest.Id); err != nil {
    75  				return nil, model.NewAppError("installPlugin", "app.plugin.install_id_failed_remove.app_error", nil, "", http.StatusBadRequest)
    76  			}
    77  		}
    78  	}
    79  
    80  	pluginPath := filepath.Join(*a.Config().PluginSettings.Directory, manifest.Id)
    81  	err = utils.CopyDir(tmpPluginDir, pluginPath)
    82  	if err != nil {
    83  		return nil, model.NewAppError("installPlugin", "app.plugin.mvdir.app_error", nil, err.Error(), http.StatusInternalServerError)
    84  	}
    85  
    86  	if stashed != nil && stashed.Enable {
    87  		a.EnablePlugin(manifest.Id)
    88  	}
    89  
    90  	if err := a.notifyPluginStatusesChanged(); err != nil {
    91  		mlog.Error("failed to notify plugin status changed", mlog.Err(err))
    92  	}
    93  
    94  	return manifest, nil
    95  }
    96  
    97  func (a *App) RemovePlugin(id string) *model.AppError {
    98  	return a.removePlugin(id)
    99  }
   100  
   101  func (a *App) removePlugin(id string) *model.AppError {
   102  	pluginsEnvironment := a.GetPluginsEnvironment()
   103  	if pluginsEnvironment == nil {
   104  		return model.NewAppError("removePlugin", "app.plugin.disabled.app_error", nil, "", http.StatusNotImplemented)
   105  	}
   106  
   107  	plugins, err := pluginsEnvironment.Available()
   108  	if err != nil {
   109  		return model.NewAppError("removePlugin", "app.plugin.deactivate.app_error", nil, err.Error(), http.StatusBadRequest)
   110  	}
   111  
   112  	var manifest *model.Manifest
   113  	var pluginPath string
   114  	for _, p := range plugins {
   115  		if p.Manifest != nil && p.Manifest.Id == id {
   116  			manifest = p.Manifest
   117  			pluginPath = filepath.Dir(p.ManifestPath)
   118  			break
   119  		}
   120  	}
   121  
   122  	if manifest == nil {
   123  		return model.NewAppError("removePlugin", "app.plugin.not_installed.app_error", nil, "", http.StatusBadRequest)
   124  	}
   125  
   126  	if pluginsEnvironment.IsActive(id) && manifest.HasClient() {
   127  		message := model.NewWebSocketEvent(model.WEBSOCKET_EVENT_PLUGIN_DISABLED, "", "", "", nil)
   128  		message.Add("manifest", manifest.ClientManifest())
   129  		a.Publish(message)
   130  	}
   131  
   132  	pluginsEnvironment.Deactivate(id)
   133  	a.UnregisterPluginCommands(id)
   134  
   135  	err = os.RemoveAll(pluginPath)
   136  	if err != nil {
   137  		return model.NewAppError("removePlugin", "app.plugin.remove.app_error", nil, err.Error(), http.StatusInternalServerError)
   138  	}
   139  
   140  	return nil
   141  }