diff --git a/plugin/helpers.go b/plugin/helpers.go index 601d3bed6b..914fc2e1f2 100644 --- a/plugin/helpers.go +++ b/plugin/helpers.go @@ -83,6 +83,12 @@ type Helpers interface { // // Minimum server version: 5.18 InstallPluginFromURL(downloadURL string, replace bool) (*model.Manifest, error) + + // GetPluginAssetURL builds a URL to the given asset in the assets directory. + // Use this URL to link to assets from the webapp, or for third-party integrations with your plugin. + // + // Minimum server version: 5.2 + GetPluginAssetURL(pluginID, asset string) (string, error) } // HelpersImpl implements the helpers interface with an API that retrieves data on behalf of the plugin. diff --git a/plugin/helpers_plugin.go b/plugin/helpers_plugin.go index 9c181a2428..4b966a5770 100644 --- a/plugin/helpers_plugin.go +++ b/plugin/helpers_plugin.go @@ -6,6 +6,7 @@ package plugin import ( "net/http" "net/url" + "path" "time" "github.com/blang/semver" @@ -54,3 +55,26 @@ func (p *HelpersImpl) ensureServerVersion(required string) error { } return nil } + +// GetPluginAssetURL implements GetPluginAssetURL. +func (p *HelpersImpl) GetPluginAssetURL(pluginID, asset string) (string, error) { + if len(pluginID) == 0 { + return "", errors.New("empty pluginID provided") + } + + if len(asset) == 0 { + return "", errors.New("empty asset name provided") + } + + siteURL := *p.API.GetConfig().ServiceSettings.SiteURL + if siteURL == "" { + return "", errors.New("no SiteURL configured by the server") + } + + u, err := url.Parse(siteURL + path.Join("/", pluginID, asset)) + if err != nil { + return "", err + } + + return u.String(), nil +} diff --git a/plugin/helpers_plugin_test.go b/plugin/helpers_plugin_test.go index 1c026ca846..6e1848a283 100644 --- a/plugin/helpers_plugin_test.go +++ b/plugin/helpers_plugin_test.go @@ -103,3 +103,74 @@ func TestInstallPluginFromURL(t *testing.T) { assert.Equal(t, "received 404 status code while downloading plugin from server", err.Error()) }) } + +func TestGetPluginAssetURL(t *testing.T) { + siteURL := "https://mattermost.example.com" + api := &plugintest.API{} + api.On("GetConfig").Return(&model.Config{ServiceSettings: model.ServiceSettings{SiteURL: &siteURL}}) + + p := &plugin.HelpersImpl{API: api} + + t.Run("Valid asset directory was provided", func(t *testing.T) { + pluginID := "mattermost-1234" + dir := "assets" + wantedURL := "https://mattermost.example.com/mattermost-1234/assets" + gotURL, err := p.GetPluginAssetURL(pluginID, dir) + + assert.Equalf(t, wantedURL, gotURL, "GetPluginAssetURL(%q, %q) got=%q; want=%v", pluginID, dir, gotURL, wantedURL) + assert.NoError(t, err) + }) + + t.Run("Valid asset directory path was provided", func(t *testing.T) { + pluginID := "mattermost-1234" + dirPath := "/mattermost/assets" + wantedURL := "https://mattermost.example.com/mattermost-1234/mattermost/assets" + gotURL, err := p.GetPluginAssetURL(pluginID, dirPath) + + assert.Equalf(t, wantedURL, gotURL, "GetPluginAssetURL(%q, %q) got=%q; want=%q", pluginID, dirPath, gotURL, wantedURL) + assert.NoError(t, err) + }) + + t.Run("Valid pluginID was provided", func(t *testing.T) { + pluginID := "mattermost-1234" + dir := "assets" + wantedURL := "https://mattermost.example.com/mattermost-1234/assets" + gotURL, err := p.GetPluginAssetURL(pluginID, dir) + + assert.Equalf(t, wantedURL, gotURL, "GetPluginAssetURL(%q, %q) got=%q; want=%q", pluginID, dir, gotURL, wantedURL) + assert.NoError(t, err) + }) + + t.Run("Invalid asset directory name was provided", func(t *testing.T) { + pluginID := "mattermost-1234" + dir := "" + want := "" + gotURL, err := p.GetPluginAssetURL(pluginID, dir) + + assert.Emptyf(t, gotURL, "GetPluginAssetURL(%q, %q) got=%s; want=%q", pluginID, dir, gotURL, want) + assert.Error(t, err) + }) + + t.Run("Invalid pluginID was provided", func(t *testing.T) { + pluginID := "" + dir := "assets" + want := "" + gotURL, err := p.GetPluginAssetURL(pluginID, dir) + + assert.Emptyf(t, gotURL, "GetPluginAssetURL(%q, %q) got=%q; want=%q", pluginID, dir, gotURL, want) + assert.Error(t, err) + }) + + siteURL = "" + api.On("GetConfig").Return(&model.Config{ServiceSettings: model.ServiceSettings{SiteURL: &siteURL}}) + + t.Run("Empty SiteURL was configured", func(t *testing.T) { + pluginID := "mattermost-1234" + dir := "assets" + want := "" + gotURL, err := p.GetPluginAssetURL(pluginID, dir) + + assert.Emptyf(t, gotURL, "GetPluginAssetURL(%q, %q) got=%q; want=%q", pluginID, dir, gotURL, want) + assert.Error(t, err) + }) +} diff --git a/plugin/plugintest/helpers.go b/plugin/plugintest/helpers.go index 9718ba0d39..48baa601a5 100644 --- a/plugin/plugintest/helpers.go +++ b/plugin/plugintest/helpers.go @@ -64,6 +64,27 @@ func (_m *Helpers) EnsureBot(bot *model.Bot, options ...plugin.EnsureBotOption) return r0, r1 } +// GetPluginAssetURL provides a mock function with given fields: pluginID, asset +func (_m *Helpers) GetPluginAssetURL(pluginID string, asset string) (string, error) { + ret := _m.Called(pluginID, asset) + + var r0 string + if rf, ok := ret.Get(0).(func(string, string) string); ok { + r0 = rf(pluginID, asset) + } else { + r0 = ret.Get(0).(string) + } + + var r1 error + if rf, ok := ret.Get(1).(func(string, string) error); ok { + r1 = rf(pluginID, asset) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // InstallPluginFromURL provides a mock function with given fields: downloadURL, replace func (_m *Helpers) InstallPluginFromURL(downloadURL string, replace bool) (*model.Manifest, error) { ret := _m.Called(downloadURL, replace)