github.com/jlevesy/mattermost-server@v5.3.2-0.20181003190404-7468f35cb0c8+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  	if a.Plugins == nil || !*a.Config().PluginSettings.Enable {
    26  		return nil, model.NewAppError("installPlugin", "app.plugin.disabled.app_error", nil, "", http.StatusNotImplemented)
    27  	}
    28  
    29  	tmpDir, err := ioutil.TempDir("", "plugintmp")
    30  	if err != nil {
    31  		return nil, model.NewAppError("installPlugin", "app.plugin.filesystem.app_error", nil, err.Error(), http.StatusInternalServerError)
    32  	}
    33  	defer os.RemoveAll(tmpDir)
    34  
    35  	if err := utils.ExtractTarGz(pluginFile, tmpDir); err != nil {
    36  		return nil, model.NewAppError("installPlugin", "app.plugin.extract.app_error", nil, err.Error(), http.StatusBadRequest)
    37  	}
    38  
    39  	tmpPluginDir := tmpDir
    40  	dir, err := ioutil.ReadDir(tmpDir)
    41  	if err != nil {
    42  		return nil, model.NewAppError("installPlugin", "app.plugin.filesystem.app_error", nil, err.Error(), http.StatusInternalServerError)
    43  	}
    44  
    45  	if len(dir) == 1 && dir[0].IsDir() {
    46  		tmpPluginDir = filepath.Join(tmpPluginDir, dir[0].Name())
    47  	}
    48  
    49  	manifest, _, err := model.FindManifest(tmpPluginDir)
    50  	if err != nil {
    51  		return nil, model.NewAppError("installPlugin", "app.plugin.manifest.app_error", nil, err.Error(), http.StatusBadRequest)
    52  	}
    53  
    54  	if !plugin.IsValidId(manifest.Id) {
    55  		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)
    56  	}
    57  
    58  	bundles, err := a.Plugins.Available()
    59  	if err != nil {
    60  		return nil, model.NewAppError("installPlugin", "app.plugin.install.app_error", nil, err.Error(), http.StatusInternalServerError)
    61  	}
    62  
    63  	// Check that there is no plugin with the same ID
    64  	for _, bundle := range bundles {
    65  		if bundle.Manifest != nil && bundle.Manifest.Id == manifest.Id {
    66  			if !replace {
    67  				return nil, model.NewAppError("installPlugin", "app.plugin.install_id.app_error", nil, "", http.StatusBadRequest)
    68  			}
    69  
    70  			if err := a.RemovePlugin(manifest.Id); err != nil {
    71  				return nil, model.NewAppError("installPlugin", "app.plugin.install_id_failed_remove.app_error", nil, "", http.StatusBadRequest)
    72  			}
    73  		}
    74  	}
    75  
    76  	pluginPath := filepath.Join(*a.Config().PluginSettings.Directory, manifest.Id)
    77  	err = utils.CopyDir(tmpPluginDir, pluginPath)
    78  	if err != nil {
    79  		return nil, model.NewAppError("installPlugin", "app.plugin.mvdir.app_error", nil, err.Error(), http.StatusInternalServerError)
    80  	}
    81  
    82  	if err := a.notifyPluginStatusesChanged(); err != nil {
    83  		mlog.Error("failed to notify plugin status changed", mlog.Err(err))
    84  	}
    85  
    86  	return manifest, nil
    87  }
    88  
    89  func (a *App) RemovePlugin(id string) *model.AppError {
    90  	return a.removePlugin(id)
    91  }
    92  
    93  func (a *App) removePlugin(id string) *model.AppError {
    94  	if a.Plugins == nil || !*a.Config().PluginSettings.Enable {
    95  		return model.NewAppError("removePlugin", "app.plugin.disabled.app_error", nil, "", http.StatusNotImplemented)
    96  	}
    97  
    98  	plugins, err := a.Plugins.Available()
    99  	if err != nil {
   100  		return model.NewAppError("removePlugin", "app.plugin.deactivate.app_error", nil, err.Error(), http.StatusBadRequest)
   101  	}
   102  
   103  	var manifest *model.Manifest
   104  	var pluginPath string
   105  	for _, p := range plugins {
   106  		if p.Manifest != nil && p.Manifest.Id == id {
   107  			manifest = p.Manifest
   108  			pluginPath = filepath.Dir(p.ManifestPath)
   109  			break
   110  		}
   111  	}
   112  
   113  	if manifest == nil {
   114  		return model.NewAppError("removePlugin", "app.plugin.not_installed.app_error", nil, "", http.StatusBadRequest)
   115  	}
   116  
   117  	if a.Plugins.IsActive(id) && manifest.HasClient() {
   118  		message := model.NewWebSocketEvent(model.WEBSOCKET_EVENT_PLUGIN_DISABLED, "", "", "", nil)
   119  		message.Add("manifest", manifest.ClientManifest())
   120  		a.Publish(message)
   121  	}
   122  
   123  	a.Plugins.Deactivate(id)
   124  
   125  	err = os.RemoveAll(pluginPath)
   126  	if err != nil {
   127  		return model.NewAppError("removePlugin", "app.plugin.remove.app_error", nil, err.Error(), http.StatusInternalServerError)
   128  	}
   129  
   130  	return nil
   131  }