From 0a736905371ae81d06244df92035840e4a805424 Mon Sep 17 00:00:00 2001 From: Hanzei <16541325+hanzei@users.noreply.github.com> Date: Tue, 20 Nov 2018 14:50:34 +0100 Subject: [PATCH 01/10] Remove *model.ChannelList from plugin API return parameter (#9844) * Remove *model.ChannelList from plugin API return parametern * Fix panic * Add tests * Changes as requested * Fix panic in GetPublicChannelsForTeam() --- app/plugin_api.go | 19 ++++++++++++++---- app/plugin_api_test.go | 36 ++++++++++++++++++++++++++++++++++ plugin/api.go | 4 ++-- plugin/client_rpc_generated.go | 12 ++++++------ plugin/plugintest/api.go | 16 +++++++-------- 5 files changed, 67 insertions(+), 20 deletions(-) diff --git a/app/plugin_api.go b/app/plugin_api.go index 78be7dbf464..64c6dc44b88 100644 --- a/app/plugin_api.go +++ b/app/plugin_api.go @@ -262,6 +262,9 @@ func (api *PluginAPI) DeleteChannel(channelId string) *model.AppError { func (api *PluginAPI) GetPublicChannelsForTeam(teamId string, page, perPage int) ([]*model.Channel, *model.AppError) { channels, err := api.app.GetPublicChannelsForTeam(teamId, page*perPage, perPage) + if err != nil { + return nil, err + } return *channels, err } @@ -277,8 +280,12 @@ func (api *PluginAPI) GetChannelByNameForTeamName(teamName, channelName string, return api.app.GetChannelByNameForTeamName(channelName, teamName, includeDeleted) } -func (api *PluginAPI) GetChannelsForTeamForUser(teamId, userId string, includeDeleted bool) (*model.ChannelList, *model.AppError) { - return api.app.GetChannelsForUser(teamId, userId, includeDeleted) +func (api *PluginAPI) GetChannelsForTeamForUser(teamId, userId string, includeDeleted bool) ([]*model.Channel, *model.AppError) { + channels, err := api.app.GetChannelsForUser(teamId, userId, includeDeleted) + if err != nil { + return nil, err + } + return *channels, err } func (api *PluginAPI) GetChannelStats(channelId string) (*model.ChannelStats, *model.AppError) { @@ -301,8 +308,12 @@ func (api *PluginAPI) UpdateChannel(channel *model.Channel) (*model.Channel, *mo return api.app.UpdateChannel(channel) } -func (api *PluginAPI) SearchChannels(teamId string, term string) (*model.ChannelList, *model.AppError) { - return api.app.SearchChannels(teamId, term) +func (api *PluginAPI) SearchChannels(teamId string, term string) ([]*model.Channel, *model.AppError) { + channels, err := api.app.SearchChannels(teamId, term) + if err != nil { + return nil, err + } + return *channels, err } func (api *PluginAPI) AddChannelMember(channelId, userId string) (*model.ChannelMember, *model.AppError) { diff --git a/app/plugin_api_test.go b/app/plugin_api_test.go index 347fd6c3271..65cca0abf8a 100644 --- a/app/plugin_api_test.go +++ b/app/plugin_api_test.go @@ -450,3 +450,39 @@ func TestPluginAPISetTeamIcon(t *testing.T) { require.Nil(t, err2) require.Equal(t, img2.At(2, 3), colorful) } + +func TestPluginAPISearchChannels(t *testing.T) { + th := Setup().InitBasic() + defer th.TearDown() + api := th.SetupPluginAPI() + + t.Run("all fine", func(t *testing.T) { + channels, err := api.SearchChannels(th.BasicTeam.Id, th.BasicChannel.Name) + assert.Nil(t, err) + assert.Len(t, channels, 1) + }) + + t.Run("invalid team id", func(t *testing.T) { + channels, err := api.SearchChannels("invalidid", th.BasicChannel.Name) + assert.Nil(t, err) + assert.Empty(t, channels) + }) +} + +func TestPluginAPIGetChannelsForTeamForUser(t *testing.T) { + th := Setup().InitBasic() + defer th.TearDown() + api := th.SetupPluginAPI() + + t.Run("all fine", func(t *testing.T) { + channels, err := api.GetChannelsForTeamForUser(th.BasicTeam.Id, th.BasicUser.Id, false) + assert.Nil(t, err) + assert.Len(t, channels, 3) + }) + + t.Run("invalid team id", func(t *testing.T) { + channels, err := api.GetChannelsForTeamForUser("invalidid", th.BasicUser.Id, false) + assert.NotNil(t, err) + assert.Empty(t, channels) + }) +} diff --git a/plugin/api.go b/plugin/api.go index 606031877c7..bd305b3bd4b 100644 --- a/plugin/api.go +++ b/plugin/api.go @@ -178,7 +178,7 @@ type API interface { // GetChannelsForTeamForUser gets a list of channels for given user ID in given team ID. // // Minimum server version: 5.6 - GetChannelsForTeamForUser(teamId, userId string, includeDeleted bool) (*model.ChannelList, *model.AppError) + GetChannelsForTeamForUser(teamId, userId string, includeDeleted bool) ([]*model.Channel, *model.AppError) // GetChannelStats gets statistics for a channel. // @@ -197,7 +197,7 @@ type API interface { // SearchChannels returns the channels on a team matching the provided search term. // // Minimum server version: 5.6 - SearchChannels(teamId string, term string) (*model.ChannelList, *model.AppError) + SearchChannels(teamId string, term string) ([]*model.Channel, *model.AppError) // AddChannelMember creates a channel membership for a user. AddChannelMember(channelId, userId string) (*model.ChannelMember, *model.AppError) diff --git a/plugin/client_rpc_generated.go b/plugin/client_rpc_generated.go index 73885017b6c..53ffcc76ca1 100644 --- a/plugin/client_rpc_generated.go +++ b/plugin/client_rpc_generated.go @@ -1778,11 +1778,11 @@ type Z_GetChannelsForTeamForUserArgs struct { } type Z_GetChannelsForTeamForUserReturns struct { - A *model.ChannelList + A []*model.Channel B *model.AppError } -func (g *apiRPCClient) GetChannelsForTeamForUser(teamId, userId string, includeDeleted bool) (*model.ChannelList, *model.AppError) { +func (g *apiRPCClient) GetChannelsForTeamForUser(teamId, userId string, includeDeleted bool) ([]*model.Channel, *model.AppError) { _args := &Z_GetChannelsForTeamForUserArgs{teamId, userId, includeDeleted} _returns := &Z_GetChannelsForTeamForUserReturns{} if err := g.client.Call("Plugin.GetChannelsForTeamForUser", _args, _returns); err != nil { @@ -1793,7 +1793,7 @@ func (g *apiRPCClient) GetChannelsForTeamForUser(teamId, userId string, includeD func (s *apiRPCServer) GetChannelsForTeamForUser(args *Z_GetChannelsForTeamForUserArgs, returns *Z_GetChannelsForTeamForUserReturns) error { if hook, ok := s.impl.(interface { - GetChannelsForTeamForUser(teamId, userId string, includeDeleted bool) (*model.ChannelList, *model.AppError) + GetChannelsForTeamForUser(teamId, userId string, includeDeleted bool) ([]*model.Channel, *model.AppError) }); ok { returns.A, returns.B = hook.GetChannelsForTeamForUser(args.A, args.B, args.C) } else { @@ -1925,11 +1925,11 @@ type Z_SearchChannelsArgs struct { } type Z_SearchChannelsReturns struct { - A *model.ChannelList + A []*model.Channel B *model.AppError } -func (g *apiRPCClient) SearchChannels(teamId string, term string) (*model.ChannelList, *model.AppError) { +func (g *apiRPCClient) SearchChannels(teamId string, term string) ([]*model.Channel, *model.AppError) { _args := &Z_SearchChannelsArgs{teamId, term} _returns := &Z_SearchChannelsReturns{} if err := g.client.Call("Plugin.SearchChannels", _args, _returns); err != nil { @@ -1940,7 +1940,7 @@ func (g *apiRPCClient) SearchChannels(teamId string, term string) (*model.Channe func (s *apiRPCServer) SearchChannels(args *Z_SearchChannelsArgs, returns *Z_SearchChannelsReturns) error { if hook, ok := s.impl.(interface { - SearchChannels(teamId string, term string) (*model.ChannelList, *model.AppError) + SearchChannels(teamId string, term string) ([]*model.Channel, *model.AppError) }); ok { returns.A, returns.B = hook.SearchChannels(args.A, args.B) } else { diff --git a/plugin/plugintest/api.go b/plugin/plugintest/api.go index 0882c5668f2..40dc29e87a6 100644 --- a/plugin/plugintest/api.go +++ b/plugin/plugintest/api.go @@ -541,15 +541,15 @@ func (_m *API) GetChannelStats(channelId string) (*model.ChannelStats, *model.Ap } // GetChannelsForTeamForUser provides a mock function with given fields: teamId, userId, includeDeleted -func (_m *API) GetChannelsForTeamForUser(teamId string, userId string, includeDeleted bool) (*model.ChannelList, *model.AppError) { +func (_m *API) GetChannelsForTeamForUser(teamId string, userId string, includeDeleted bool) ([]*model.Channel, *model.AppError) { ret := _m.Called(teamId, userId, includeDeleted) - var r0 *model.ChannelList - if rf, ok := ret.Get(0).(func(string, string, bool) *model.ChannelList); ok { + var r0 []*model.Channel + if rf, ok := ret.Get(0).(func(string, string, bool) []*model.Channel); ok { r0 = rf(teamId, userId, includeDeleted) } else { if ret.Get(0) != nil { - r0 = ret.Get(0).(*model.ChannelList) + r0 = ret.Get(0).([]*model.Channel) } } @@ -1866,15 +1866,15 @@ func (_m *API) SavePluginConfig(pluginConfig map[string]interface{}) *model.AppE } // SearchChannels provides a mock function with given fields: teamId, term -func (_m *API) SearchChannels(teamId string, term string) (*model.ChannelList, *model.AppError) { +func (_m *API) SearchChannels(teamId string, term string) ([]*model.Channel, *model.AppError) { ret := _m.Called(teamId, term) - var r0 *model.ChannelList - if rf, ok := ret.Get(0).(func(string, string) *model.ChannelList); ok { + var r0 []*model.Channel + if rf, ok := ret.Get(0).(func(string, string) []*model.Channel); ok { r0 = rf(teamId, term) } else { if ret.Get(0) != nil { - r0 = ret.Get(0).(*model.ChannelList) + r0 = ret.Get(0).([]*model.Channel) } } From c46d8ec892d40c50d9a235ac455e082502284c54 Mon Sep 17 00:00:00 2001 From: Jesse Hallam Date: Tue, 20 Nov 2018 08:52:51 -0500 Subject: [PATCH 02/10] MM-12974: guard app plugins with mutex (#9818) * guard app plugins with mutex Shutting down the app could race with a goroutine that uses the plugins environment, since we shut down the plugins first before cleaning up goroutines. * fix go vet issues --- app/channel.go | 21 ++++----- app/diagnostics.go | 99 +++++++++++++++++++++------------------- app/file.go | 4 +- app/login.go | 6 +-- app/plugin.go | 98 ++++++++++++++++++++++++++------------- app/plugin_api_test.go | 10 ++-- app/plugin_commands.go | 12 +++-- app/plugin_hooks_test.go | 2 +- app/plugin_install.go | 14 +++--- app/plugin_requests.go | 5 +- app/plugin_statuses.go | 10 ++-- app/plugin_test.go | 1 + app/post.go | 16 +++---- app/server.go | 3 +- app/team.go | 8 ++-- 15 files changed, 178 insertions(+), 131 deletions(-) diff --git a/app/channel.go b/app/channel.go index 99265f3408c..6e4f1b103a5 100644 --- a/app/channel.go +++ b/app/channel.go @@ -211,10 +211,10 @@ func (a *App) CreateChannel(channel *model.Channel, addMember bool) (*model.Chan a.InvalidateCacheForUser(channel.CreatorId) } - if a.PluginsReady() { + if pluginsEnvironment := a.GetPluginsEnvironment(); pluginsEnvironment != nil { a.Srv.Go(func() { pluginContext := &plugin.Context{} - a.Srv.Plugins.RunMultiPluginHook(func(hooks plugin.Hooks) bool { + pluginsEnvironment.RunMultiPluginHook(func(hooks plugin.Hooks) bool { hooks.ChannelHasBeenCreated(pluginContext, sc) return true }, plugin.ChannelHasBeenCreatedId) @@ -238,10 +238,10 @@ func (a *App) CreateDirectChannel(userId string, otherUserId string) (*model.Cha a.InvalidateCacheForUser(userId) a.InvalidateCacheForUser(otherUserId) - if a.PluginsReady() { + if pluginsEnvironment := a.GetPluginsEnvironment(); pluginsEnvironment != nil { a.Srv.Go(func() { pluginContext := &plugin.Context{} - a.Srv.Plugins.RunMultiPluginHook(func(hooks plugin.Hooks) bool { + pluginsEnvironment.RunMultiPluginHook(func(hooks plugin.Hooks) bool { hooks.ChannelHasBeenCreated(pluginContext, channel) return true }, plugin.ChannelHasBeenCreatedId) @@ -857,10 +857,10 @@ func (a *App) AddChannelMember(userId string, channel *model.Channel, userReques return nil, err } - if a.PluginsReady() { + if pluginsEnvironment := a.GetPluginsEnvironment(); pluginsEnvironment != nil { a.Srv.Go(func() { pluginContext := &plugin.Context{} - a.Srv.Plugins.RunMultiPluginHook(func(hooks plugin.Hooks) bool { + pluginsEnvironment.RunMultiPluginHook(func(hooks plugin.Hooks) bool { hooks.UserHasJoinedChannel(pluginContext, cm, userRequestor) return true }, plugin.UserHasJoinedChannelId) @@ -1247,10 +1247,10 @@ func (a *App) JoinChannel(channel *model.Channel, userId string) *model.AppError return err } - if a.PluginsReady() { + if pluginsEnvironment := a.GetPluginsEnvironment(); pluginsEnvironment != nil { a.Srv.Go(func() { pluginContext := &plugin.Context{} - a.Srv.Plugins.RunMultiPluginHook(func(hooks plugin.Hooks) bool { + pluginsEnvironment.RunMultiPluginHook(func(hooks plugin.Hooks) bool { hooks.UserHasJoinedChannel(pluginContext, cm, nil) return true }, plugin.UserHasJoinedChannelId) @@ -1448,8 +1448,7 @@ func (a *App) removeUserFromChannel(userIdToRemove string, removerUserId string, a.InvalidateCacheForUser(userIdToRemove) a.InvalidateCacheForChannelMembers(channel.Id) - if a.PluginsReady() { - + if pluginsEnvironment := a.GetPluginsEnvironment(); pluginsEnvironment != nil { var actorUser *model.User if removerUserId != "" { actorUser, _ = a.GetUser(removerUserId) @@ -1457,7 +1456,7 @@ func (a *App) removeUserFromChannel(userIdToRemove string, removerUserId string, a.Srv.Go(func() { pluginContext := &plugin.Context{} - a.Srv.Plugins.RunMultiPluginHook(func(hooks plugin.Hooks) bool { + pluginsEnvironment.RunMultiPluginHook(func(hooks plugin.Hooks) bool { hooks.UserHasLeftChannel(pluginContext, cm, actorUser) return true }, plugin.UserHasLeftChannelId) diff --git a/app/diagnostics.go b/app/diagnostics.go index c706ce4bf26..d75ea5b99b9 100644 --- a/app/diagnostics.go +++ b/app/diagnostics.go @@ -580,62 +580,65 @@ func (a *App) trackLicense() { } func (a *App) trackPlugins() { - if a.PluginsReady() { - totalEnabledCount := 0 - webappEnabledCount := 0 - backendEnabledCount := 0 - totalDisabledCount := 0 - webappDisabledCount := 0 - backendDisabledCount := 0 - brokenManifestCount := 0 - settingsCount := 0 + pluginsEnvironment := a.GetPluginsEnvironment() + if pluginsEnvironment == nil { + return + } - pluginStates := a.Config().PluginSettings.PluginStates - plugins, _ := a.Srv.Plugins.Available() + totalEnabledCount := 0 + webappEnabledCount := 0 + backendEnabledCount := 0 + totalDisabledCount := 0 + webappDisabledCount := 0 + backendDisabledCount := 0 + brokenManifestCount := 0 + settingsCount := 0 - if pluginStates != nil && plugins != nil { - for _, plugin := range plugins { - if plugin.Manifest == nil { - brokenManifestCount += 1 - continue + pluginStates := a.Config().PluginSettings.PluginStates + plugins, _ := pluginsEnvironment.Available() + + if pluginStates != nil && plugins != nil { + for _, plugin := range plugins { + if plugin.Manifest == nil { + brokenManifestCount += 1 + continue + } + if state, ok := pluginStates[plugin.Manifest.Id]; ok && state.Enable { + totalEnabledCount += 1 + if plugin.Manifest.HasServer() { + backendEnabledCount += 1 } - if state, ok := pluginStates[plugin.Manifest.Id]; ok && state.Enable { - totalEnabledCount += 1 - if plugin.Manifest.HasServer() { - backendEnabledCount += 1 - } - if plugin.Manifest.HasWebapp() { - webappEnabledCount += 1 - } - } else { - totalDisabledCount += 1 - if plugin.Manifest.HasServer() { - backendDisabledCount += 1 - } - if plugin.Manifest.HasWebapp() { - webappDisabledCount += 1 - } + if plugin.Manifest.HasWebapp() { + webappEnabledCount += 1 } - if plugin.Manifest.SettingsSchema != nil { - settingsCount += 1 + } else { + totalDisabledCount += 1 + if plugin.Manifest.HasServer() { + backendDisabledCount += 1 + } + if plugin.Manifest.HasWebapp() { + webappDisabledCount += 1 } } - } else { - totalEnabledCount = -1 // -1 to indicate disabled or error - totalDisabledCount = -1 // -1 to indicate disabled or error + if plugin.Manifest.SettingsSchema != nil { + settingsCount += 1 + } } - - a.SendDiagnostic(TRACK_PLUGINS, map[string]interface{}{ - "enabled_plugins": totalEnabledCount, - "enabled_webapp_plugins": webappEnabledCount, - "enabled_backend_plugins": backendEnabledCount, - "disabled_plugins": totalDisabledCount, - "disabled_webapp_plugins": webappDisabledCount, - "disabled_backend_plugins": backendDisabledCount, - "plugins_with_settings": settingsCount, - "plugins_with_broken_manifests": brokenManifestCount, - }) + } else { + totalEnabledCount = -1 // -1 to indicate disabled or error + totalDisabledCount = -1 // -1 to indicate disabled or error } + + a.SendDiagnostic(TRACK_PLUGINS, map[string]interface{}{ + "enabled_plugins": totalEnabledCount, + "enabled_webapp_plugins": webappEnabledCount, + "enabled_backend_plugins": backendEnabledCount, + "disabled_plugins": totalDisabledCount, + "disabled_webapp_plugins": webappDisabledCount, + "disabled_backend_plugins": backendDisabledCount, + "plugins_with_settings": settingsCount, + "plugins_with_broken_manifests": brokenManifestCount, + }) } func (a *App) trackServer() { diff --git a/app/file.go b/app/file.go index 410e3ae9b36..dccc177932d 100644 --- a/app/file.go +++ b/app/file.go @@ -460,10 +460,10 @@ func (a *App) DoUploadFileExpectModification(now time.Time, rawTeamId string, ra info.ThumbnailPath = pathPrefix + nameWithoutExtension + "_thumb.jpg" } - if a.PluginsReady() { + if pluginsEnvironment := a.GetPluginsEnvironment(); pluginsEnvironment != nil { var rejectionError *model.AppError pluginContext := &plugin.Context{} - a.Srv.Plugins.RunMultiPluginHook(func(hooks plugin.Hooks) bool { + pluginsEnvironment.RunMultiPluginHook(func(hooks plugin.Hooks) bool { var newBytes bytes.Buffer replacementInfo, rejectionReason := hooks.FileWillBeUploaded(pluginContext, info, bytes.NewReader(data), &newBytes) if rejectionReason != "" { diff --git a/app/login.go b/app/login.go index 28f207f75f8..5e97f7f5860 100644 --- a/app/login.go +++ b/app/login.go @@ -66,10 +66,10 @@ func (a *App) AuthenticateUserForLogin(id, loginId, password, mfaToken string, l return nil, err } - if a.PluginsReady() { + if pluginsEnvironment := a.GetPluginsEnvironment(); pluginsEnvironment != nil { var rejectionReason string pluginContext := &plugin.Context{} - a.Srv.Plugins.RunMultiPluginHook(func(hooks plugin.Hooks) bool { + pluginsEnvironment.RunMultiPluginHook(func(hooks plugin.Hooks) bool { rejectionReason = hooks.UserWillLogIn(pluginContext, user) return rejectionReason == "" }, plugin.UserWillLogInId) @@ -80,7 +80,7 @@ func (a *App) AuthenticateUserForLogin(id, loginId, password, mfaToken string, l a.Srv.Go(func() { pluginContext := &plugin.Context{} - a.Srv.Plugins.RunMultiPluginHook(func(hooks plugin.Hooks) bool { + pluginsEnvironment.RunMultiPluginHook(func(hooks plugin.Hooks) bool { hooks.UserHasLoggedIn(pluginContext, user) return true }, plugin.UserHasLoggedInId) diff --git a/app/plugin.go b/app/plugin.go index 2c1eb3862ad..962d153412b 100644 --- a/app/plugin.go +++ b/app/plugin.go @@ -15,22 +15,49 @@ import ( "github.com/mattermost/mattermost-server/utils" ) +// GetPluginsEnvironment returns the plugin environment for use if plugins are enabled and +// initialized. +// +// To get the plugins environment when the plugins are disabled, manually acquire the plugins +// lock instead. +func (a *App) GetPluginsEnvironment() *plugin.Environment { + if !*a.Config().PluginSettings.Enable { + return nil + } + + a.Srv.PluginsLock.RLock() + defer a.Srv.PluginsLock.RUnlock() + + return a.Srv.PluginsEnvironment +} + +func (a *App) SetPluginsEnvironment(pluginsEnvironment *plugin.Environment) { + a.Srv.PluginsLock.Lock() + defer a.Srv.PluginsLock.Unlock() + + a.Srv.PluginsEnvironment = pluginsEnvironment +} + func (a *App) SyncPluginsActiveState() { - if a.Srv.Plugins == nil { + a.Srv.PluginsLock.RLock() + pluginsEnvironment := a.Srv.PluginsEnvironment + a.Srv.PluginsLock.RUnlock() + + if pluginsEnvironment == nil { return } config := a.Config().PluginSettings if *config.Enable { - availablePlugins, err := a.Srv.Plugins.Available() + availablePlugins, err := pluginsEnvironment.Available() if err != nil { a.Log.Error("Unable to get available plugins", mlog.Err(err)) return } // Deactivate any plugins that have been disabled. - for _, plugin := range a.Srv.Plugins.Active() { + for _, plugin := range pluginsEnvironment.Active() { // Determine if plugin is enabled pluginId := plugin.Manifest.Id pluginEnabled := false @@ -40,7 +67,7 @@ func (a *App) SyncPluginsActiveState() { // If it's not enabled we need to deactivate it if !pluginEnabled { - deactivated := a.Srv.Plugins.Deactivate(pluginId) + deactivated := pluginsEnvironment.Deactivate(pluginId) if deactivated && plugin.Manifest.HasClient() { message := model.NewWebSocketEvent(model.WEBSOCKET_EVENT_PLUGIN_DISABLED, "", "", "", nil) message.Add("manifest", plugin.Manifest.ClientManifest()) @@ -65,7 +92,7 @@ func (a *App) SyncPluginsActiveState() { // Activate plugin if enabled if pluginEnabled { - updatedManifest, activated, err := a.Srv.Plugins.Activate(pluginId) + updatedManifest, activated, err := pluginsEnvironment.Activate(pluginId) if err != nil { plugin.WrapLogger(a.Log).Error("Unable to activate plugin", mlog.Err(err)) continue @@ -79,7 +106,7 @@ func (a *App) SyncPluginsActiveState() { } } } else { // If plugins are disabled, shutdown plugins. - a.Srv.Plugins.Shutdown() + pluginsEnvironment.Shutdown() } if err := a.notifyPluginStatusesChanged(); err != nil { @@ -92,7 +119,10 @@ func (a *App) NewPluginAPI(manifest *model.Manifest) plugin.API { } func (a *App) InitPlugins(pluginDir, webappPluginDir string) { - if a.Srv.Plugins != nil || !*a.Config().PluginSettings.Enable { + a.Srv.PluginsLock.RLock() + pluginsEnvironment := a.Srv.PluginsEnvironment + a.Srv.PluginsLock.RUnlock() + if pluginsEnvironment != nil || !*a.Config().PluginSettings.Enable { a.SyncPluginsActiveState() return } @@ -109,12 +139,12 @@ func (a *App) InitPlugins(pluginDir, webappPluginDir string) { return } - if env, err := plugin.NewEnvironment(a.NewPluginAPI, pluginDir, webappPluginDir, a.Log); err != nil { + env, err := plugin.NewEnvironment(a.NewPluginAPI, pluginDir, webappPluginDir, a.Log) + if err != nil { mlog.Error("Failed to start up plugins", mlog.Err(err)) return - } else { - a.Srv.Plugins = env } + a.SetPluginsEnvironment(env) prepackagedPluginsDir, found := utils.FindDir("prepackaged_plugins") if found { @@ -136,39 +166,46 @@ func (a *App) InitPlugins(pluginDir, webappPluginDir string) { } // Sync plugin active state when config changes. Also notify plugins. + a.Srv.PluginsLock.Lock() a.RemoveConfigListener(a.Srv.PluginConfigListenerId) a.Srv.PluginConfigListenerId = a.AddConfigListener(func(*model.Config, *model.Config) { a.SyncPluginsActiveState() - a.Srv.Plugins.RunMultiPluginHook(func(hooks plugin.Hooks) bool { - hooks.OnConfigurationChange() - return true - }, plugin.OnConfigurationChangeId) + if pluginsEnvironment := a.GetPluginsEnvironment(); pluginsEnvironment != nil { + pluginsEnvironment.RunMultiPluginHook(func(hooks plugin.Hooks) bool { + hooks.OnConfigurationChange() + return true + }, plugin.OnConfigurationChangeId) + } }) + a.Srv.PluginsLock.Unlock() a.SyncPluginsActiveState() - } func (a *App) ShutDownPlugins() { - if a.Srv.Plugins == nil { + a.Srv.PluginsLock.Lock() + pluginsEnvironment := a.Srv.PluginsEnvironment + defer a.Srv.PluginsLock.Unlock() + if pluginsEnvironment == nil { return } mlog.Info("Shutting down plugins") - a.Srv.Plugins.Shutdown() + pluginsEnvironment.Shutdown() a.RemoveConfigListener(a.Srv.PluginConfigListenerId) a.Srv.PluginConfigListenerId = "" - a.Srv.Plugins = nil + a.Srv.PluginsEnvironment = nil } func (a *App) GetActivePluginManifests() ([]*model.Manifest, *model.AppError) { - if a.Srv.Plugins == nil || !*a.Config().PluginSettings.Enable { + pluginsEnvironment := a.GetPluginsEnvironment() + if pluginsEnvironment == nil { return nil, model.NewAppError("GetActivePluginManifests", "app.plugin.disabled.app_error", nil, "", http.StatusNotImplemented) } - plugins := a.Srv.Plugins.Active() + plugins := pluginsEnvironment.Active() manifests := make([]*model.Manifest, len(plugins)) for i, plugin := range plugins { @@ -181,11 +218,12 @@ func (a *App) GetActivePluginManifests() ([]*model.Manifest, *model.AppError) { // EnablePlugin will set the config for an installed plugin to enabled, triggering asynchronous // activation if inactive anywhere in the cluster. func (a *App) EnablePlugin(id string) *model.AppError { - if a.Srv.Plugins == nil || !*a.Config().PluginSettings.Enable { + pluginsEnvironment := a.GetPluginsEnvironment() + if pluginsEnvironment == nil { return model.NewAppError("EnablePlugin", "app.plugin.disabled.app_error", nil, "", http.StatusNotImplemented) } - plugins, err := a.Srv.Plugins.Available() + plugins, err := pluginsEnvironment.Available() if err != nil { return model.NewAppError("EnablePlugin", "app.plugin.config.app_error", nil, err.Error(), http.StatusInternalServerError) } @@ -221,11 +259,12 @@ func (a *App) EnablePlugin(id string) *model.AppError { // DisablePlugin will set the config for an installed plugin to disabled, triggering deactivation if active. func (a *App) DisablePlugin(id string) *model.AppError { - if a.Srv.Plugins == nil || !*a.Config().PluginSettings.Enable { + pluginsEnvironment := a.GetPluginsEnvironment() + if pluginsEnvironment == nil { return model.NewAppError("DisablePlugin", "app.plugin.disabled.app_error", nil, "", http.StatusNotImplemented) } - plugins, err := a.Srv.Plugins.Available() + plugins, err := pluginsEnvironment.Available() if err != nil { return model.NewAppError("DisablePlugin", "app.plugin.config.app_error", nil, err.Error(), http.StatusInternalServerError) } @@ -255,16 +294,13 @@ func (a *App) DisablePlugin(id string) *model.AppError { return nil } -func (a *App) PluginsReady() bool { - return a.Srv.Plugins != nil && *a.Config().PluginSettings.Enable -} - func (a *App) GetPlugins() (*model.PluginsResponse, *model.AppError) { - if !a.PluginsReady() { + pluginsEnvironment := a.GetPluginsEnvironment() + if pluginsEnvironment == nil { return nil, model.NewAppError("GetPlugins", "app.plugin.disabled.app_error", nil, "", http.StatusNotImplemented) } - availablePlugins, err := a.Srv.Plugins.Available() + availablePlugins, err := pluginsEnvironment.Available() if err != nil { return nil, model.NewAppError("GetPlugins", "app.plugin.get_plugins.app_error", nil, err.Error(), http.StatusInternalServerError) } @@ -278,7 +314,7 @@ func (a *App) GetPlugins() (*model.PluginsResponse, *model.AppError) { Manifest: *plugin.Manifest, } - if a.Srv.Plugins.IsActive(plugin.Manifest.Id) { + if pluginsEnvironment.IsActive(plugin.Manifest.Id) { resp.Active = append(resp.Active, info) } else { resp.Inactive = append(resp.Inactive, info) diff --git a/app/plugin_api_test.go b/app/plugin_api_test.go index 65cca0abf8a..8fc2e1dfd90 100644 --- a/app/plugin_api_test.go +++ b/app/plugin_api_test.go @@ -41,7 +41,7 @@ func setupPluginApiTest(t *testing.T, pluginCode string, pluginManifest string, require.NotNil(t, manifest) require.True(t, activated) - app.Srv.Plugins = env + app.SetPluginsEnvironment(env) } func TestPluginAPIUpdateUserStatus(t *testing.T) { @@ -206,7 +206,7 @@ func TestPluginAPILoadPluginConfiguration(t *testing.T) { } ] }}`, "testloadpluginconfig", th.App) - hooks, err := th.App.Srv.Plugins.HooksForPlugin("testloadpluginconfig") + hooks, err := th.App.GetPluginsEnvironment().HooksForPlugin("testloadpluginconfig") assert.NoError(t, err) _, ret := hooks.MessageWillBePosted(nil, nil) assert.Equal(t, "str32true", ret) @@ -280,7 +280,7 @@ func TestPluginAPILoadPluginConfigurationDefaults(t *testing.T) { } ] }}`, "testloadpluginconfig", th.App) - hooks, err := th.App.Srv.Plugins.HooksForPlugin("testloadpluginconfig") + hooks, err := th.App.GetPluginsEnvironment().HooksForPlugin("testloadpluginconfig") assert.NoError(t, err) _, ret := hooks.MessageWillBePosted(nil, nil) assert.Equal(t, "override35true", ret) @@ -377,9 +377,9 @@ func TestPluginAPIGetPlugins(t *testing.T) { require.True(t, activated) pluginManifests = append(pluginManifests, manifest) } - th.App.Srv.Plugins = env + th.App.SetPluginsEnvironment(env) - // Decative the last one for testing + // Decativate the last one for testing sucess := env.Deactivate(pluginIDs[len(pluginIDs)-1]) require.True(t, sucess) diff --git a/app/plugin_commands.go b/app/plugin_commands.go index cbaeb507c95..911f54cec1e 100644 --- a/app/plugin_commands.go +++ b/app/plugin_commands.go @@ -101,12 +101,14 @@ func (a *App) ExecutePluginCommand(args *model.CommandArgs) (*model.Command, *mo for _, pc := range a.Srv.pluginCommands { if (pc.Command.TeamId == "" || pc.Command.TeamId == args.TeamId) && pc.Command.Trigger == trigger { - pluginHooks, err := a.Srv.Plugins.HooksForPlugin(pc.PluginId) - if err != nil { - return pc.Command, nil, model.NewAppError("ExecutePluginCommand", "model.plugin_command.error.app_error", nil, "err="+err.Error(), http.StatusInternalServerError) + if pluginsEnvironment := a.GetPluginsEnvironment(); pluginsEnvironment != nil { + pluginHooks, err := pluginsEnvironment.HooksForPlugin(pc.PluginId) + if err != nil { + return pc.Command, nil, model.NewAppError("ExecutePluginCommand", "model.plugin_command.error.app_error", nil, "err="+err.Error(), http.StatusInternalServerError) + } + response, appErr := pluginHooks.ExecuteCommand(&plugin.Context{}, args) + return pc.Command, response, appErr } - response, appErr := pluginHooks.ExecuteCommand(&plugin.Context{}, args) - return pc.Command, response, appErr } } return nil, nil, nil diff --git a/app/plugin_hooks_test.go b/app/plugin_hooks_test.go index 9016b84e46d..ca3ff46cec4 100644 --- a/app/plugin_hooks_test.go +++ b/app/plugin_hooks_test.go @@ -44,7 +44,7 @@ func SetAppEnvironmentWithPlugins(t *testing.T, pluginCode []string, app *App, a env, err := plugin.NewEnvironment(apiFunc, pluginDir, webappPluginDir, app.Log) require.NoError(t, err) - app.Srv.Plugins = env + app.SetPluginsEnvironment(env) pluginIds := []string{} activationErrors := []error{} for _, code := range pluginCode { diff --git a/app/plugin_install.go b/app/plugin_install.go index aaa6e46a533..8fbd0bc6232 100644 --- a/app/plugin_install.go +++ b/app/plugin_install.go @@ -22,7 +22,8 @@ func (a *App) InstallPlugin(pluginFile io.Reader, replace bool) (*model.Manifest } func (a *App) installPlugin(pluginFile io.Reader, replace bool) (*model.Manifest, *model.AppError) { - if a.Srv.Plugins == nil || !*a.Config().PluginSettings.Enable { + pluginsEnvironment := a.GetPluginsEnvironment() + if pluginsEnvironment == nil { return nil, model.NewAppError("installPlugin", "app.plugin.disabled.app_error", nil, "", http.StatusNotImplemented) } @@ -55,7 +56,7 @@ func (a *App) installPlugin(pluginFile io.Reader, replace bool) (*model.Manifest 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) } - bundles, err := a.Srv.Plugins.Available() + bundles, err := pluginsEnvironment.Available() if err != nil { return nil, model.NewAppError("installPlugin", "app.plugin.install.app_error", nil, err.Error(), http.StatusInternalServerError) } @@ -91,11 +92,12 @@ func (a *App) RemovePlugin(id string) *model.AppError { } func (a *App) removePlugin(id string) *model.AppError { - if a.Srv.Plugins == nil || !*a.Config().PluginSettings.Enable { + pluginsEnvironment := a.GetPluginsEnvironment() + if pluginsEnvironment == nil { return model.NewAppError("removePlugin", "app.plugin.disabled.app_error", nil, "", http.StatusNotImplemented) } - plugins, err := a.Srv.Plugins.Available() + plugins, err := pluginsEnvironment.Available() if err != nil { return model.NewAppError("removePlugin", "app.plugin.deactivate.app_error", nil, err.Error(), http.StatusBadRequest) } @@ -114,13 +116,13 @@ func (a *App) removePlugin(id string) *model.AppError { return model.NewAppError("removePlugin", "app.plugin.not_installed.app_error", nil, "", http.StatusBadRequest) } - if a.Srv.Plugins.IsActive(id) && manifest.HasClient() { + if pluginsEnvironment.IsActive(id) && manifest.HasClient() { message := model.NewWebSocketEvent(model.WEBSOCKET_EVENT_PLUGIN_DISABLED, "", "", "", nil) message.Add("manifest", manifest.ClientManifest()) a.Publish(message) } - a.Srv.Plugins.Deactivate(id) + pluginsEnvironment.Deactivate(id) a.UnregisterPluginCommands(id) err = os.RemoveAll(pluginPath) diff --git a/app/plugin_requests.go b/app/plugin_requests.go index 4070a060f43..e3ebc604217 100644 --- a/app/plugin_requests.go +++ b/app/plugin_requests.go @@ -19,7 +19,8 @@ import ( ) func (a *App) ServePluginRequest(w http.ResponseWriter, r *http.Request) { - if a.Srv.Plugins == nil || !*a.Config().PluginSettings.Enable { + pluginsEnvironment := a.GetPluginsEnvironment() + if pluginsEnvironment == nil { err := model.NewAppError("ServePluginRequest", "app.plugin.disabled.app_error", nil, "Enable plugins to serve plugin requests", http.StatusNotImplemented) a.Log.Error(err.Error()) w.WriteHeader(err.StatusCode) @@ -29,7 +30,7 @@ func (a *App) ServePluginRequest(w http.ResponseWriter, r *http.Request) { } params := mux.Vars(r) - hooks, err := a.Srv.Plugins.HooksForPlugin(params["plugin_id"]) + hooks, err := pluginsEnvironment.HooksForPlugin(params["plugin_id"]) if err != nil { a.Log.Error("Access to route for non-existent plugin", mlog.String("missing_plugin_id", params["plugin_id"]), mlog.Err(err)) http.NotFound(w, r) diff --git a/app/plugin_statuses.go b/app/plugin_statuses.go index fc5561bcfc3..fe397dd8460 100644 --- a/app/plugin_statuses.go +++ b/app/plugin_statuses.go @@ -11,11 +11,12 @@ import ( // GetPluginStatus returns the status for a plugin installed on this server. func (a *App) GetPluginStatus(id string) (*model.PluginStatus, *model.AppError) { - if a.Srv.Plugins == nil || !*a.Config().PluginSettings.Enable { + pluginsEnvironment := a.GetPluginsEnvironment() + if pluginsEnvironment == nil { return nil, model.NewAppError("GetPluginStatus", "app.plugin.disabled.app_error", nil, "", http.StatusNotImplemented) } - pluginStatuses, err := a.Srv.Plugins.Statuses() + pluginStatuses, err := pluginsEnvironment.Statuses() if err != nil { return nil, model.NewAppError("GetPluginStatus", "app.plugin.get_statuses.app_error", nil, err.Error(), http.StatusInternalServerError) } @@ -32,11 +33,12 @@ func (a *App) GetPluginStatus(id string) (*model.PluginStatus, *model.AppError) // GetPluginStatuses returns the status for plugins installed on this server. func (a *App) GetPluginStatuses() (model.PluginStatuses, *model.AppError) { - if a.Srv.Plugins == nil || !*a.Config().PluginSettings.Enable { + pluginsEnvironment := a.GetPluginsEnvironment() + if pluginsEnvironment == nil { return nil, model.NewAppError("GetPluginStatuses", "app.plugin.disabled.app_error", nil, "", http.StatusNotImplemented) } - pluginStatuses, err := a.Srv.Plugins.Statuses() + pluginStatuses, err := pluginsEnvironment.Statuses() if err != nil { return nil, model.NewAppError("GetPluginStatuses", "app.plugin.get_statuses.app_error", nil, err.Error(), http.StatusInternalServerError) } diff --git a/app/plugin_test.go b/app/plugin_test.go index 8dcae9b16d5..0221a763e42 100644 --- a/app/plugin_test.go +++ b/app/plugin_test.go @@ -198,6 +198,7 @@ func TestGetPluginStatusesDisabled(t *testing.T) { }) _, err := th.App.GetPluginStatuses() + require.NotNil(t, err) require.EqualError(t, err, "GetPluginStatuses: Plugins have been disabled. Please check your logs for details., ") } diff --git a/app/post.go b/app/post.go index c4909a9d42d..882c3edb65a 100644 --- a/app/post.go +++ b/app/post.go @@ -144,10 +144,10 @@ func (a *App) CreatePost(post *model.Post, channel *model.Channel, triggerWebhoo return nil, err } - if a.PluginsReady() { + if pluginsEnvironment := a.GetPluginsEnvironment(); pluginsEnvironment != nil { var rejectionError *model.AppError pluginContext := &plugin.Context{} - a.Srv.Plugins.RunMultiPluginHook(func(hooks plugin.Hooks) bool { + pluginsEnvironment.RunMultiPluginHook(func(hooks plugin.Hooks) bool { replacementPost, rejectionReason := hooks.MessageWillBePosted(pluginContext, post) if rejectionReason != "" { rejectionError = model.NewAppError("createPost", "Post rejected by plugin. "+rejectionReason, nil, "", http.StatusBadRequest) @@ -170,10 +170,10 @@ func (a *App) CreatePost(post *model.Post, channel *model.Channel, triggerWebhoo } rpost := result.Data.(*model.Post) - if a.PluginsReady() { + if pluginsEnvironment := a.GetPluginsEnvironment(); pluginsEnvironment != nil { a.Srv.Go(func() { pluginContext := &plugin.Context{} - a.Srv.Plugins.RunMultiPluginHook(func(hooks plugin.Hooks) bool { + pluginsEnvironment.RunMultiPluginHook(func(hooks plugin.Hooks) bool { hooks.MessageHasBeenPosted(pluginContext, rpost) return true }, plugin.MessageHasBeenPostedId) @@ -356,10 +356,10 @@ func (a *App) UpdatePost(post *model.Post, safeUpdate bool) (*model.Post, *model return nil, err } - if a.PluginsReady() { + if pluginsEnvironment := a.GetPluginsEnvironment(); pluginsEnvironment != nil { var rejectionReason string pluginContext := &plugin.Context{} - a.Srv.Plugins.RunMultiPluginHook(func(hooks plugin.Hooks) bool { + pluginsEnvironment.RunMultiPluginHook(func(hooks plugin.Hooks) bool { newPost, rejectionReason = hooks.MessageWillBeUpdated(pluginContext, newPost, oldPost) return post != nil }, plugin.MessageWillBeUpdatedId) @@ -374,10 +374,10 @@ func (a *App) UpdatePost(post *model.Post, safeUpdate bool) (*model.Post, *model } rpost := result.Data.(*model.Post) - if a.PluginsReady() { + if pluginsEnvironment := a.GetPluginsEnvironment(); pluginsEnvironment != nil { a.Srv.Go(func() { pluginContext := &plugin.Context{} - a.Srv.Plugins.RunMultiPluginHook(func(hooks plugin.Hooks) bool { + pluginsEnvironment.RunMultiPluginHook(func(hooks plugin.Hooks) bool { hooks.MessageHasBeenUpdated(pluginContext, newPost, oldPost) return true }, plugin.MessageHasBeenUpdatedId) diff --git a/app/server.go b/app/server.go index 53e5e039da1..ed91b92f2a5 100644 --- a/app/server.go +++ b/app/server.go @@ -54,8 +54,9 @@ type Server struct { goroutineCount int32 goroutineExitSignal chan struct{} - Plugins *plugin.Environment + PluginsEnvironment *plugin.Environment PluginConfigListenerId string + PluginsLock sync.RWMutex EmailBatching *EmailBatchingJob EmailRateLimiter *throttled.GCRARateLimiter diff --git a/app/team.go b/app/team.go index 0152cbb6af7..f8a74a78f6a 100644 --- a/app/team.go +++ b/app/team.go @@ -461,7 +461,7 @@ func (a *App) JoinUserToTeam(team *model.Team, user *model.User, userRequestorId return nil } - if a.PluginsReady() { + if pluginsEnvironment := a.GetPluginsEnvironment(); pluginsEnvironment != nil { var actor *model.User if userRequestorId != "" { actor, _ = a.GetUser(userRequestorId) @@ -469,7 +469,7 @@ func (a *App) JoinUserToTeam(team *model.Team, user *model.User, userRequestorId a.Srv.Go(func() { pluginContext := &plugin.Context{} - a.Srv.Plugins.RunMultiPluginHook(func(hooks plugin.Hooks) bool { + pluginsEnvironment.RunMultiPluginHook(func(hooks plugin.Hooks) bool { hooks.UserHasJoinedTeam(pluginContext, tm, actor) return true }, plugin.UserHasJoinedTeamId) @@ -784,7 +784,7 @@ func (a *App) LeaveTeam(team *model.Team, user *model.User, requestorId string) return result.Err } - if a.PluginsReady() { + if pluginsEnvironment := a.GetPluginsEnvironment(); pluginsEnvironment != nil { var actor *model.User if requestorId != "" { actor, _ = a.GetUser(requestorId) @@ -792,7 +792,7 @@ func (a *App) LeaveTeam(team *model.Team, user *model.User, requestorId string) a.Srv.Go(func() { pluginContext := &plugin.Context{} - a.Srv.Plugins.RunMultiPluginHook(func(hooks plugin.Hooks) bool { + pluginsEnvironment.RunMultiPluginHook(func(hooks plugin.Hooks) bool { hooks.UserHasLeftTeam(pluginContext, teamMember, actor) return true }, plugin.UserHasLeftTeamId) From 2555a5d45d78a1645e6ff143cfcd3fe76a224f27 Mon Sep 17 00:00:00 2001 From: Carlos Tadeu Panato Junior Date: Tue, 20 Nov 2018 15:43:42 +0100 Subject: [PATCH 03/10] Add RemoveTeamIcon plugin api (#9847) --- app/plugin_api.go | 13 +++++++++++++ app/plugin_api_test.go | 31 +++++++++++++++++++++++++++---- plugin/api.go | 9 +++++++-- plugin/client_rpc_generated.go | 28 ++++++++++++++++++++++++++++ plugin/plugintest/api.go | 16 ++++++++++++++++ 5 files changed, 91 insertions(+), 6 deletions(-) diff --git a/app/plugin_api.go b/app/plugin_api.go index 64c6dc44b88..d6b601332e1 100644 --- a/app/plugin_api.go +++ b/app/plugin_api.go @@ -510,6 +510,19 @@ func (api *PluginAPI) OpenInteractiveDialog(dialog model.OpenDialogRequest) *mod return api.app.OpenInteractiveDialog(dialog) } +func (api *PluginAPI) RemoveTeamIcon(teamId string) *model.AppError { + _, err := api.app.GetTeam(teamId) + if err != nil { + return err + } + + err = api.app.RemoveTeamIcon(teamId) + if err != nil { + return err + } + return nil +} + // Plugin Section func (api *PluginAPI) GetPlugins() ([]*model.Manifest, *model.AppError) { diff --git a/app/plugin_api_test.go b/app/plugin_api_test.go index 8fc2e1dfd90..e17dda9763c 100644 --- a/app/plugin_api_test.go +++ b/app/plugin_api_test.go @@ -87,18 +87,18 @@ func TestPluginAPISavePluginConfig(t *testing.T) { t.Fatal(err) } - if err := api.SavePluginConfig(pluginConfig); err != nil{ + if err := api.SavePluginConfig(pluginConfig); err != nil { t.Fatal(err) } type Configuration struct { MyStringSetting string - MyIntSetting int - MyBoolSetting bool + MyIntSetting int + MyBoolSetting bool } savedConfiguration := new(Configuration) - if err := api.LoadPluginConfiguration(savedConfiguration); err != nil{ + if err := api.LoadPluginConfiguration(savedConfiguration); err != nil { t.Fatal(err) } @@ -486,3 +486,26 @@ func TestPluginAPIGetChannelsForTeamForUser(t *testing.T) { assert.Empty(t, channels) }) } + +func TestPluginAPIRemoveTeamIcon(t *testing.T) { + th := Setup().InitBasic() + defer th.TearDown() + api := th.SetupPluginAPI() + + // Create an 128 x 128 image + img := image.NewRGBA(image.Rect(0, 0, 128, 128)) + + // Draw a red dot at (2, 3) + img.Set(2, 3, color.RGBA{255, 0, 0, 255}) + buf := new(bytes.Buffer) + err1 := png.Encode(buf, img) + require.Nil(t, err1) + dataBytes := buf.Bytes() + fileReader := bytes.NewReader(dataBytes) + + // Set the Team Icon + err := th.App.SetTeamIconFromFile(th.BasicTeam, fileReader) + require.Nil(t, err) + err = api.RemoveTeamIcon(th.BasicTeam.Id) + require.Nil(t, err) +} diff --git a/plugin/api.go b/plugin/api.go index bd305b3bd4b..93f73ff08db 100644 --- a/plugin/api.go +++ b/plugin/api.go @@ -74,16 +74,21 @@ type API interface { // Minimum server version: 5.6 GetUsersInTeam(teamId string, page int, perPage int) ([]*model.User, *model.AppError) - // GetTeamIcon gets the Team Icon. + // GetTeamIcon gets the team icon. // // Minimum server version: 5.6 GetTeamIcon(teamId string) ([]byte, *model.AppError) - // SetTeamIcon sets the Team Icon. + // SetTeamIcon sets the team icon. // // Minimum server version: 5.6 SetTeamIcon(teamId string, data []byte) *model.AppError + // RemoveTeamIcon removes the team icon. + // + // Minimum server version: 5.6 + RemoveTeamIcon(teamId string) *model.AppError + // UpdateUser updates a user. UpdateUser(user *model.User) (*model.User, *model.AppError) diff --git a/plugin/client_rpc_generated.go b/plugin/client_rpc_generated.go index 53ffcc76ca1..a3520748454 100644 --- a/plugin/client_rpc_generated.go +++ b/plugin/client_rpc_generated.go @@ -1000,6 +1000,34 @@ func (s *apiRPCServer) SetTeamIcon(args *Z_SetTeamIconArgs, returns *Z_SetTeamIc return nil } +type Z_RemoveTeamIconArgs struct { + A string +} + +type Z_RemoveTeamIconReturns struct { + A *model.AppError +} + +func (g *apiRPCClient) RemoveTeamIcon(teamId string) *model.AppError { + _args := &Z_RemoveTeamIconArgs{teamId} + _returns := &Z_RemoveTeamIconReturns{} + if err := g.client.Call("Plugin.RemoveTeamIcon", _args, _returns); err != nil { + log.Printf("RPC call to RemoveTeamIcon API failed: %s", err.Error()) + } + return _returns.A +} + +func (s *apiRPCServer) RemoveTeamIcon(args *Z_RemoveTeamIconArgs, returns *Z_RemoveTeamIconReturns) error { + if hook, ok := s.impl.(interface { + RemoveTeamIcon(teamId string) *model.AppError + }); ok { + returns.A = hook.RemoveTeamIcon(args.A) + } else { + return encodableError(fmt.Errorf("API RemoveTeamIcon called but not implemented.")) + } + return nil +} + type Z_UpdateUserArgs struct { A *model.User } diff --git a/plugin/plugintest/api.go b/plugin/plugintest/api.go index 40dc29e87a6..5abde3308db 100644 --- a/plugin/plugintest/api.go +++ b/plugin/plugintest/api.go @@ -1833,6 +1833,22 @@ func (_m *API) RemoveReaction(reaction *model.Reaction) *model.AppError { return r0 } +// RemoveTeamIcon provides a mock function with given fields: teamId +func (_m *API) RemoveTeamIcon(teamId string) *model.AppError { + ret := _m.Called(teamId) + + var r0 *model.AppError + if rf, ok := ret.Get(0).(func(string) *model.AppError); ok { + r0 = rf(teamId) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*model.AppError) + } + } + + return r0 +} + // SaveConfig provides a mock function with given fields: config func (_m *API) SaveConfig(config *model.Config) *model.AppError { ret := _m.Called(config) From a78913178c68220cb9bd105cab5d7fad4d697161 Mon Sep 17 00:00:00 2001 From: Jesse Hallam Date: Tue, 20 Nov 2018 20:16:25 -0500 Subject: [PATCH 04/10] Ensure unittest isolation (#9819) * api4: fix TestGetUsersNotInTeam assertions This test was relying on data from a previous test run. With the data cleared before each test, the assertions much match reality. * *testlib: always InitSystemAdmin Some tests implicitly relied on the basic user having system administrator privileges because it was the first user created as such. Eliminate `InitSystemAdmin` and explicitly create the system admin user instead to avoid this ambiguity going forward. * *testlib: drop all tables before each test * api4: split up TestChannelDelete to avoid duplicate InitBasic * api4: teardown in TestResetPassword, for when this test comes back * invalidate cache on DropAllTables This is necessary since the test store persists across tests. * disable parallel tests While tests within a package must be explicitly parallelized using `t.Parallel()`, tests across packages are run in parallel by default. This causes problems given that the tests all currently share the same database instance. Unfortunately, this also means that running the tests is much slower, but we can return to this later. --- Makefile | 2 +- api4/apitestlib.go | 74 ++----------------- api4/brand_test.go | 6 +- api4/channel_test.go | 80 ++++++++++---------- api4/cluster_test.go | 2 +- api4/command_test.go | 18 ++--- api4/elasticsearch_test.go | 4 +- api4/emoji_test.go | 4 +- api4/file_test.go | 16 ++-- api4/job_test.go | 10 +-- api4/ldap_test.go | 4 +- api4/oauth_test.go | 20 ++--- api4/plugin_test.go | 2 +- api4/post_test.go | 34 ++++----- api4/reaction_test.go | 6 +- api4/role_test.go | 8 +- api4/saml_test.go | 2 +- api4/scheme_test.go | 14 ++-- api4/status_test.go | 2 +- api4/system_test.go | 36 ++++----- api4/team_test.go | 72 +++++++++--------- api4/terms_of_service_test.go | 2 +- api4/user_test.go | 97 ++++++++++++------------- api4/webhook_test.go | 22 +++--- app/apptestlib.go | 17 +++-- app/channel_test.go | 2 +- app/web_conn_test.go | 2 +- cmd/mattermost/commands/command_test.go | 1 - cmd/mattermost/commands/plugin_test.go | 2 +- cmd/mattermost/commands/team_test.go | 4 +- cmd/mattermost/commands/user_test.go | 2 +- cmd/mattermost/commands/webhook_test.go | 8 +- migrations/migrationstestlib.go | 16 ++-- store/layered_store.go | 1 + store/local_cache_supplier.go | 6 ++ 35 files changed, 271 insertions(+), 327 deletions(-) diff --git a/Makefile b/Makefile index 2233b2652ce..5790d5fa54f 100644 --- a/Makefile +++ b/Makefile @@ -351,7 +351,7 @@ test-te: do-cover-file ## Runs tests in the team edition. @echo Testing TE @echo "Packages to test: "$(TE_PACKAGES) find . -name 'cprofile*.out' -exec sh -c 'rm "{}"' \; - $(GO) test $(GOFLAGS) -run=$(TESTS) $(TESTFLAGS) -v -timeout=2000s -covermode=count -coverpkg=$(ALL_PACKAGES_COMMA) -exec $(ROOT)/scripts/test-xprog.sh $(TE_PACKAGES) + $(GO) test $(GOFLAGS) -run=$(TESTS) $(TESTFLAGS) -p 1 -v -timeout=2000s -covermode=count -coverpkg=$(ALL_PACKAGES_COMMA) -exec $(ROOT)/scripts/test-xprog.sh $(TE_PACKAGES) find . -name 'cprofile*.out' -exec sh -c 'tail -n +2 {} >> cover.out ; rm "{}"' \; test-ee: do-cover-file ## Runs tests in the enterprise edition. diff --git a/api4/apitestlib.go b/api4/apitestlib.go index 9976932a9af..0a843dfab53 100644 --- a/api4/apitestlib.go +++ b/api4/apitestlib.go @@ -15,7 +15,6 @@ import ( "reflect" "strconv" "strings" - "sync" "testing" "time" @@ -77,6 +76,10 @@ func StopTestStore() { } func setupTestHelper(enterprise bool, updateConfig func(*model.Config)) *TestHelper { + if testStore != nil { + testStore.DropAllTables() + } + permConfig, err := os.Open(utils.FindConfigFile("config.json")) if err != nil { panic(err) @@ -179,61 +182,6 @@ func SetupConfig(updateConfig func(cfg *model.Config)) *TestHelper { func (me *TestHelper) TearDown() { utils.DisableDebugLogForTest() - var wg sync.WaitGroup - wg.Add(3) - - go func() { - defer wg.Done() - options := &model.UserSearchOptions{ - AllowEmails: false, - AllowFullNames: false, - Limit: model.USER_SEARCH_MAX_LIMIT, - } - if result := <-me.App.Srv.Store.User().Search("", "fakeuser", options); result.Err != nil { - mlog.Error("Error tearing down test users") - } else { - users := result.Data.([]*model.User) - - for _, u := range users { - if err := me.App.PermanentDeleteUser(u); err != nil { - mlog.Error(err.Error()) - } - } - } - }() - - go func() { - defer wg.Done() - if result := <-me.App.Srv.Store.Team().SearchByName("faketeam"); result.Err != nil { - mlog.Error("Error tearing down test teams") - } else { - teams := result.Data.([]*model.Team) - - for _, t := range teams { - if err := me.App.PermanentDeleteTeam(t); err != nil { - mlog.Error(err.Error()) - } - } - } - }() - - go func() { - defer wg.Done() - if result := <-me.App.Srv.Store.OAuth().GetApps(0, 1000); result.Err != nil { - mlog.Error("Error tearing down test oauth apps") - } else { - apps := result.Data.([]*model.OAuthApp) - - for _, a := range apps { - if strings.HasPrefix(a.Name, "fakeoauthapp") { - <-me.App.Srv.Store.OAuth().DeleteApp(a.Id) - } - } - } - }() - - wg.Wait() - me.App.Shutdown() os.Remove(me.tempConfigPath) @@ -248,6 +196,10 @@ func (me *TestHelper) TearDown() { func (me *TestHelper) InitBasic() *TestHelper { me.waitForConnectivity() + me.SystemAdminUser = me.CreateUser() + me.App.UpdateUserRoles(me.SystemAdminUser.Id, model.SYSTEM_USER_ROLE_ID+" "+model.SYSTEM_ADMIN_ROLE_ID, false) + me.LoginSystemAdmin() + me.TeamAdminUser = me.CreateUser() me.App.UpdateUserRoles(me.TeamAdminUser.Id, model.SYSTEM_USER_ROLE_ID, false) me.LoginTeamAdmin() @@ -276,16 +228,6 @@ func (me *TestHelper) InitBasic() *TestHelper { return me } -func (me *TestHelper) InitSystemAdmin() *TestHelper { - me.waitForConnectivity() - - me.SystemAdminUser = me.CreateUser() - me.App.UpdateUserRoles(me.SystemAdminUser.Id, model.SYSTEM_USER_ROLE_ID+" "+model.SYSTEM_ADMIN_ROLE_ID, false) - me.LoginSystemAdmin() - - return me -} - func (me *TestHelper) waitForConnectivity() { for i := 0; i < 1000; i++ { conn, err := net.Dial("tcp", fmt.Sprintf("localhost:%v", me.App.Srv.ListenAddr.Port)) diff --git a/api4/brand_test.go b/api4/brand_test.go index 37169d99a62..d222757fa25 100644 --- a/api4/brand_test.go +++ b/api4/brand_test.go @@ -9,7 +9,7 @@ import ( ) func TestGetBrandImage(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client @@ -25,7 +25,7 @@ func TestGetBrandImage(t *testing.T) { } func TestUploadBrandImage(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client @@ -54,7 +54,7 @@ func TestUploadBrandImage(t *testing.T) { } func TestDeleteBrandImage(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() data, err := readTestFile("test.png") diff --git a/api4/channel_test.go b/api4/channel_test.go index d588c0c25f4..2daa66c5493 100644 --- a/api4/channel_test.go +++ b/api4/channel_test.go @@ -20,7 +20,7 @@ import ( ) func TestCreateChannel(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client team := th.BasicTeam @@ -142,7 +142,7 @@ func TestCreateChannel(t *testing.T) { } func TestUpdateChannel(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client team := th.BasicTeam @@ -240,7 +240,7 @@ func TestUpdateChannel(t *testing.T) { } func TestPatchChannel(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client @@ -326,7 +326,7 @@ func TestPatchChannel(t *testing.T) { } func TestCreateDirectChannel(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client user1 := th.BasicUser @@ -378,7 +378,7 @@ func TestCreateDirectChannel(t *testing.T) { } func TestDeleteDirectChannel(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client user := th.BasicUser @@ -395,7 +395,7 @@ func TestDeleteDirectChannel(t *testing.T) { } func TestCreateGroupChannel(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client user := th.BasicUser @@ -467,7 +467,7 @@ func TestCreateGroupChannel(t *testing.T) { } func TestDeleteGroupChannel(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client user := th.BasicUser @@ -487,7 +487,7 @@ func TestDeleteGroupChannel(t *testing.T) { } func TestGetChannel(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client @@ -536,7 +536,7 @@ func TestGetChannel(t *testing.T) { } func TestGetDeletedChannelsForTeam(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client team := th.BasicTeam @@ -583,7 +583,7 @@ func TestGetDeletedChannelsForTeam(t *testing.T) { } func TestGetPublicChannelsForTeam(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client team := th.BasicTeam @@ -663,7 +663,7 @@ func TestGetPublicChannelsForTeam(t *testing.T) { } func TestGetPublicChannelsByIdsForTeam(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client teamId := th.BasicTeam.Id @@ -725,7 +725,7 @@ func TestGetPublicChannelsByIdsForTeam(t *testing.T) { } func TestGetChannelsForTeamForUser(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client @@ -773,7 +773,7 @@ func TestGetChannelsForTeamForUser(t *testing.T) { } func TestSearchChannels(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client @@ -828,7 +828,7 @@ func TestSearchChannels(t *testing.T) { } func TestDeleteChannel(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client team := th.BasicTeam @@ -915,8 +915,13 @@ func TestDeleteChannel(t *testing.T) { _, resp = th.SystemAdminClient.DeleteChannel(publicChannel5.Id) CheckNoError(t, resp) +} - th.InitBasic().InitSystemAdmin() +func TestDeleteChannel2(t *testing.T) { + th := Setup().InitBasic() + defer th.TearDown() + Client := th.Client + user := th.BasicUser // Check the appropriate permissions are enforced. defaultRolePermissions := th.SaveDefaultRolePermissions() @@ -927,9 +932,6 @@ func TestDeleteChannel(t *testing.T) { th.AddPermissionToRole(model.PERMISSION_DELETE_PUBLIC_CHANNEL.Id, model.TEAM_USER_ROLE_ID) th.AddPermissionToRole(model.PERMISSION_DELETE_PRIVATE_CHANNEL.Id, model.TEAM_USER_ROLE_ID) - Client = th.Client - user = th.BasicUser - // channels created by SystemAdmin publicChannel6 := th.CreateChannelWithClient(th.SystemAdminClient, model.CHANNEL_OPEN) privateChannel7 := th.CreateChannelWithClient(th.SystemAdminClient, model.CHANNEL_PRIVATE) @@ -938,7 +940,7 @@ func TestDeleteChannel(t *testing.T) { th.App.AddUserToChannel(user, privateChannel7) // successful delete by user - _, resp = Client.DeleteChannel(publicChannel6.Id) + _, resp := Client.DeleteChannel(publicChannel6.Id) CheckNoError(t, resp) _, resp = Client.DeleteChannel(privateChannel7.Id) @@ -991,7 +993,7 @@ func TestDeleteChannel(t *testing.T) { } func TestConvertChannelToPrivate(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client @@ -1065,7 +1067,7 @@ func TestConvertChannelToPrivate(t *testing.T) { } func TestRestoreChannel(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client @@ -1091,7 +1093,7 @@ func TestRestoreChannel(t *testing.T) { } func TestGetChannelByName(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client @@ -1150,7 +1152,7 @@ func TestGetChannelByName(t *testing.T) { } func TestGetChannelByNameForTeamName(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client @@ -1191,7 +1193,7 @@ func TestGetChannelByNameForTeamName(t *testing.T) { } func TestGetChannelMembers(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client @@ -1246,7 +1248,7 @@ func TestGetChannelMembers(t *testing.T) { } func TestGetChannelMembersByIds(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client @@ -1293,7 +1295,7 @@ func TestGetChannelMembersByIds(t *testing.T) { } func TestGetChannelMember(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client @@ -1340,7 +1342,7 @@ func TestGetChannelMember(t *testing.T) { } func TestGetChannelMembersForUser(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client @@ -1383,7 +1385,7 @@ func TestGetChannelMembersForUser(t *testing.T) { } func TestViewChannel(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client @@ -1454,7 +1456,7 @@ func TestViewChannel(t *testing.T) { } func TestGetChannelUnread(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client user := th.BasicUser @@ -1498,7 +1500,7 @@ func TestGetChannelUnread(t *testing.T) { } func TestGetChannelStats(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client channel := th.CreatePrivateChannel() @@ -1532,7 +1534,7 @@ func TestGetChannelStats(t *testing.T) { } func TestGetPinnedPosts(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client channel := th.BasicChannel @@ -1571,7 +1573,7 @@ func TestGetPinnedPosts(t *testing.T) { } func TestUpdateChannelRoles(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client @@ -1650,7 +1652,7 @@ func TestUpdateChannelRoles(t *testing.T) { } func TestUpdateChannelMemberSchemeRoles(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() SystemAdminClient := th.SystemAdminClient th.LoginBasic() @@ -1725,7 +1727,7 @@ func TestUpdateChannelMemberSchemeRoles(t *testing.T) { } func TestUpdateChannelNotifyProps(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client @@ -1775,7 +1777,7 @@ func TestUpdateChannelNotifyProps(t *testing.T) { } func TestAddChannelMember(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client user := th.BasicUser @@ -1934,7 +1936,7 @@ func TestAddChannelMember(t *testing.T) { } func TestRemoveChannelMember(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() user1 := th.BasicUser user2 := th.BasicUser2 team := th.BasicTeam @@ -2138,7 +2140,7 @@ func TestAutocompleteChannels(t *testing.T) { } func TestAutocompleteChannelsForSearch(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() th.LoginSystemAdminWithClient(th.SystemAdminClient) @@ -2261,7 +2263,7 @@ func TestAutocompleteChannelsForSearch(t *testing.T) { } func TestUpdateChannelScheme(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() th.App.SetLicense(model.NewTestLicense("")) @@ -2337,7 +2339,7 @@ func TestUpdateChannelScheme(t *testing.T) { } func TestGetChannelMembersTimezones(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client diff --git a/api4/cluster_test.go b/api4/cluster_test.go index 8a0ffd1c4b5..3e0ba5212fa 100644 --- a/api4/cluster_test.go +++ b/api4/cluster_test.go @@ -8,7 +8,7 @@ import ( ) func TestGetClusterStatus(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() _, resp := th.Client.GetClusterStatus() diff --git a/api4/command_test.go b/api4/command_test.go index cffedd1d810..bb206667757 100644 --- a/api4/command_test.go +++ b/api4/command_test.go @@ -16,7 +16,7 @@ import ( ) func TestCreateCommand(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client @@ -65,7 +65,7 @@ func TestCreateCommand(t *testing.T) { } func TestUpdateCommand(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.SystemAdminClient user := th.SystemAdminUser @@ -151,7 +151,7 @@ func TestUpdateCommand(t *testing.T) { } func TestDeleteCommand(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.SystemAdminClient user := th.SystemAdminUser @@ -214,7 +214,7 @@ func TestDeleteCommand(t *testing.T) { } func TestListCommands(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client @@ -297,7 +297,7 @@ func TestListCommands(t *testing.T) { } func TestListAutocompleteCommands(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client @@ -357,7 +357,7 @@ func TestListAutocompleteCommands(t *testing.T) { } func TestRegenToken(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client @@ -392,7 +392,7 @@ func TestRegenToken(t *testing.T) { } func TestExecuteInvalidCommand(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client channel := th.BasicChannel @@ -455,7 +455,7 @@ func TestExecuteInvalidCommand(t *testing.T) { } func TestExecuteGetCommand(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client channel := th.BasicChannel @@ -517,7 +517,7 @@ func TestExecuteGetCommand(t *testing.T) { } func TestExecutePostCommand(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client channel := th.BasicChannel diff --git a/api4/elasticsearch_test.go b/api4/elasticsearch_test.go index 5aae5ebcdbf..c1037303f71 100644 --- a/api4/elasticsearch_test.go +++ b/api4/elasticsearch_test.go @@ -8,7 +8,7 @@ import ( ) func TestElasticsearchTest(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() _, resp := th.Client.TestElasticsearch() @@ -19,7 +19,7 @@ func TestElasticsearchTest(t *testing.T) { } func TestElasticsearchPurgeIndexes(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() _, resp := th.Client.PurgeElasticsearchIndexes() diff --git a/api4/emoji_test.go b/api4/emoji_test.go index e3aca4497cd..64e155b7c2a 100644 --- a/api4/emoji_test.go +++ b/api4/emoji_test.go @@ -17,7 +17,7 @@ import ( ) func TestCreateEmoji(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client @@ -259,7 +259,7 @@ func TestGetEmojiList(t *testing.T) { } func TestDeleteEmoji(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client diff --git a/api4/file_test.go b/api4/file_test.go index 607e54dd7cd..5d0d5ab4dfc 100644 --- a/api4/file_test.go +++ b/api4/file_test.go @@ -15,7 +15,7 @@ import ( ) func TestUploadFileAsMultipart(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client @@ -128,7 +128,7 @@ func TestUploadFileAsMultipart(t *testing.T) { } func TestUploadFileAsRequestBody(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client @@ -251,7 +251,7 @@ func TestUploadFileAsRequestBody(t *testing.T) { } func TestGetFile(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client channel := th.BasicChannel @@ -366,7 +366,7 @@ func TestGetFileHeaders(t *testing.T) { } func TestGetFileThumbnail(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client channel := th.BasicChannel @@ -418,7 +418,7 @@ func TestGetFileThumbnail(t *testing.T) { } func TestGetFileLink(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client channel := th.BasicChannel @@ -494,7 +494,7 @@ func TestGetFileLink(t *testing.T) { } func TestGetFilePreview(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client channel := th.BasicChannel @@ -546,7 +546,7 @@ func TestGetFilePreview(t *testing.T) { } func TestGetFileInfo(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client user := th.BasicUser @@ -613,7 +613,7 @@ func TestGetFileInfo(t *testing.T) { } func TestGetPublicFile(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client channel := th.BasicChannel diff --git a/api4/job_test.go b/api4/job_test.go index 685cab4d118..2ba69c37b0d 100644 --- a/api4/job_test.go +++ b/api4/job_test.go @@ -12,7 +12,7 @@ import ( ) func TestCreateJob(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() job := &model.Job{ @@ -39,7 +39,7 @@ func TestCreateJob(t *testing.T) { } func TestGetJob(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() job := &model.Job{ @@ -70,7 +70,7 @@ func TestGetJob(t *testing.T) { } func TestGetJobs(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() jobType := model.NewId() @@ -122,7 +122,7 @@ func TestGetJobs(t *testing.T) { } func TestGetJobsByType(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() jobType := model.NewId() @@ -186,7 +186,7 @@ func TestGetJobsByType(t *testing.T) { } func TestCancelJob(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() jobs := []*model.Job{ diff --git a/api4/ldap_test.go b/api4/ldap_test.go index d259bbb4a75..5c7f53b1d0a 100644 --- a/api4/ldap_test.go +++ b/api4/ldap_test.go @@ -8,7 +8,7 @@ import ( ) func TestLdapTest(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() _, resp := th.Client.TestLdap() @@ -19,7 +19,7 @@ func TestLdapTest(t *testing.T) { } func TestLdapSync(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() _, resp := th.SystemAdminClient.SyncLdap() diff --git a/api4/oauth_test.go b/api4/oauth_test.go index dcc7cc5a26c..31497677d5c 100644 --- a/api4/oauth_test.go +++ b/api4/oauth_test.go @@ -23,7 +23,7 @@ import ( ) func TestCreateOAuthApp(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client AdminClient := th.SystemAdminClient @@ -96,7 +96,7 @@ func TestCreateOAuthApp(t *testing.T) { } func TestUpdateOAuthApp(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client AdminClient := th.SystemAdminClient @@ -213,7 +213,7 @@ func TestUpdateOAuthApp(t *testing.T) { } func TestGetOAuthApps(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client AdminClient := th.SystemAdminClient @@ -287,7 +287,7 @@ func TestGetOAuthApps(t *testing.T) { } func TestGetOAuthApp(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client AdminClient := th.SystemAdminClient @@ -363,7 +363,7 @@ func TestGetOAuthApp(t *testing.T) { } func TestGetOAuthAppInfo(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client AdminClient := th.SystemAdminClient @@ -439,7 +439,7 @@ func TestGetOAuthAppInfo(t *testing.T) { } func TestDeleteOAuthApp(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client AdminClient := th.SystemAdminClient @@ -509,7 +509,7 @@ func TestDeleteOAuthApp(t *testing.T) { } func TestRegenerateOAuthAppSecret(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client AdminClient := th.SystemAdminClient @@ -583,7 +583,7 @@ func TestRegenerateOAuthAppSecret(t *testing.T) { } func TestGetAuthorizedOAuthAppsForUser(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client AdminClient := th.SystemAdminClient @@ -643,7 +643,7 @@ func TestGetAuthorizedOAuthAppsForUser(t *testing.T) { } func TestAuthorizeOAuthApp(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client AdminClient := th.SystemAdminClient @@ -732,7 +732,7 @@ func TestAuthorizeOAuthApp(t *testing.T) { } func TestDeauthorizeOAuthApp(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client AdminClient := th.SystemAdminClient diff --git a/api4/plugin_test.go b/api4/plugin_test.go index 9500b2019e6..1a1bccfdf07 100644 --- a/api4/plugin_test.go +++ b/api4/plugin_test.go @@ -16,7 +16,7 @@ import ( ) func TestPlugin(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() enablePlugins := *th.App.Config().PluginSettings.Enable diff --git a/api4/post_test.go b/api4/post_test.go index 7cac2e18a1b..08b9ed12ff5 100644 --- a/api4/post_test.go +++ b/api4/post_test.go @@ -23,7 +23,7 @@ import ( ) func TestCreatePost(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client @@ -120,7 +120,7 @@ func TestCreatePost(t *testing.T) { } func TestCreatePostEphemeral(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.SystemAdminClient @@ -167,7 +167,7 @@ func testCreatePostWithOutgoingHook( triggerWhen int, commentPostType bool, ) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() user := th.SystemAdminUser team := th.BasicTeam @@ -356,7 +356,7 @@ func TestCreatePostWithOutgoingHook_no_content_type(t *testing.T) { } func TestCreatePostPublic(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client @@ -401,7 +401,7 @@ func TestCreatePostPublic(t *testing.T) { } func TestCreatePostAll(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client @@ -456,7 +456,7 @@ func TestCreatePostAll(t *testing.T) { } func TestCreatePostSendOutOfChannelMentions(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client @@ -523,7 +523,7 @@ func TestCreatePostSendOutOfChannelMentions(t *testing.T) { } func TestUpdatePost(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client channel := th.BasicChannel @@ -603,7 +603,7 @@ func TestUpdateOthersPostInDirectMessageChannel(t *testing.T) { // This test checks that a sysadmin with the "EDIT_OTHERS_POSTS" permission can edit someone else's post in a // channel without a team (DM/GM). This indirectly checks for the proper cascading all the way to system-wide roles // on the user object of permissions based on a post in a channel with no team ID. - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() dmChannel := th.CreateDmChannel(th.SystemAdminUser) @@ -625,7 +625,7 @@ func TestUpdateOthersPostInDirectMessageChannel(t *testing.T) { } func TestPatchPost(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client channel := th.BasicChannel @@ -713,7 +713,7 @@ func TestPatchPost(t *testing.T) { } func TestPinPost(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client @@ -748,7 +748,7 @@ func TestPinPost(t *testing.T) { } func TestUnpinPost(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client @@ -783,7 +783,7 @@ func TestUnpinPost(t *testing.T) { } func TestGetPostsForChannel(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client @@ -895,7 +895,7 @@ func TestGetPostsForChannel(t *testing.T) { } func TestGetFlaggedPostsForUser(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client user := th.BasicUser @@ -1160,7 +1160,7 @@ func TestGetPostsAfterAndBefore(t *testing.T) { } func TestGetPost(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client @@ -1209,7 +1209,7 @@ func TestGetPost(t *testing.T) { } func TestDeletePost(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client @@ -1247,7 +1247,7 @@ func TestDeletePost(t *testing.T) { } func TestGetPostThread(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client @@ -1676,7 +1676,7 @@ func TestSearchPostsWithDateFlags(t *testing.T) { } func TestGetFileInfosForPost(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client diff --git a/api4/reaction_test.go b/api4/reaction_test.go index aa7e3fdb889..7a0ade49386 100644 --- a/api4/reaction_test.go +++ b/api4/reaction_test.go @@ -13,7 +13,7 @@ import ( ) func TestSaveReaction(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client userId := th.BasicUser.Id @@ -225,7 +225,7 @@ func TestSaveReaction(t *testing.T) { } func TestGetReactions(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client userId := th.BasicUser.Id @@ -306,7 +306,7 @@ func TestGetReactions(t *testing.T) { } func TestDeleteReaction(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client userId := th.BasicUser.Id diff --git a/api4/role_test.go b/api4/role_test.go index 2a8008dc947..3d0caa0201e 100644 --- a/api4/role_test.go +++ b/api4/role_test.go @@ -13,7 +13,7 @@ import ( ) func TestGetRole(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() role := &model.Role{ @@ -47,7 +47,7 @@ func TestGetRole(t *testing.T) { } func TestGetRoleByName(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() role := &model.Role{ @@ -81,7 +81,7 @@ func TestGetRoleByName(t *testing.T) { } func TestGetRolesByNames(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() role1 := &model.Role{ @@ -147,7 +147,7 @@ func TestGetRolesByNames(t *testing.T) { } func TestPatchRole(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() role := &model.Role{ diff --git a/api4/saml_test.go b/api4/saml_test.go index ef0dfb8cbc6..57383afba79 100644 --- a/api4/saml_test.go +++ b/api4/saml_test.go @@ -8,7 +8,7 @@ import ( ) func TestGetSamlMetadata(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client diff --git a/api4/scheme_test.go b/api4/scheme_test.go index 21a94ca69a8..aba1f032ca9 100644 --- a/api4/scheme_test.go +++ b/api4/scheme_test.go @@ -13,7 +13,7 @@ import ( ) func TestCreateScheme(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() th.App.SetLicense(model.NewTestLicense("custom_permissions_schemes")) @@ -150,7 +150,7 @@ func TestCreateScheme(t *testing.T) { } func TestGetScheme(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() th.App.SetLicense(model.NewTestLicense("custom_permissions_schemes")) @@ -210,7 +210,7 @@ func TestGetScheme(t *testing.T) { } func TestGetSchemes(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() th.App.SetLicense(model.NewTestLicense("custom_permissions_schemes")) @@ -273,7 +273,7 @@ func TestGetSchemes(t *testing.T) { } func TestGetTeamsForScheme(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() th.App.SetLicense(model.NewTestLicense("custom_permissions_schemes")) @@ -368,7 +368,7 @@ func TestGetTeamsForScheme(t *testing.T) { } func TestGetChannelsForScheme(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() th.App.SetLicense(model.NewTestLicense("custom_permissions_schemes")) @@ -465,7 +465,7 @@ func TestGetChannelsForScheme(t *testing.T) { } func TestPatchScheme(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() th.App.SetLicense(model.NewTestLicense("custom_permissions_schemes")) @@ -570,7 +570,7 @@ func TestPatchScheme(t *testing.T) { } func TestDeleteScheme(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() t.Run("ValidTeamScheme", func(t *testing.T) { diff --git a/api4/status_test.go b/api4/status_test.go index ddfc879aea4..ced87c0d7b3 100644 --- a/api4/status_test.go +++ b/api4/status_test.go @@ -117,7 +117,7 @@ func TestGetUsersStatusesByIds(t *testing.T) { } func TestUpdateUserStatus(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client diff --git a/api4/system_test.go b/api4/system_test.go index fe56794aa33..ba7d9b24a21 100644 --- a/api4/system_test.go +++ b/api4/system_test.go @@ -15,7 +15,7 @@ import ( ) func TestGetPing(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client @@ -39,7 +39,7 @@ func TestGetPing(t *testing.T) { } func TestGetConfig(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client @@ -84,7 +84,7 @@ func TestGetConfig(t *testing.T) { } func TestReloadConfig(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client @@ -105,7 +105,7 @@ func TestReloadConfig(t *testing.T) { } func TestUpdateConfig(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client @@ -152,7 +152,7 @@ func TestGetEnvironmentConfig(t *testing.T) { os.Setenv("MM_SERVICESETTINGS_ENABLECUSTOMEMOJI", "true") defer os.Unsetenv("MM_SERVICESETTINGS_SITEURL") - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() t.Run("as system admin", func(t *testing.T) { @@ -212,7 +212,7 @@ func TestGetEnvironmentConfig(t *testing.T) { } func TestGetOldClientConfig(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() testKey := "supersecretkey" @@ -274,7 +274,7 @@ func TestGetOldClientConfig(t *testing.T) { } func TestGetOldClientLicense(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client @@ -307,7 +307,7 @@ func TestGetOldClientLicense(t *testing.T) { } func TestGetAudits(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client @@ -344,7 +344,7 @@ func TestGetAudits(t *testing.T) { } func TestEmailTest(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client @@ -379,7 +379,7 @@ func TestEmailTest(t *testing.T) { } func TestDatabaseRecycle(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client @@ -391,7 +391,7 @@ func TestDatabaseRecycle(t *testing.T) { } func TestInvalidateCaches(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client @@ -409,7 +409,7 @@ func TestInvalidateCaches(t *testing.T) { } func TestGetLogs(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client @@ -449,7 +449,7 @@ func TestGetLogs(t *testing.T) { } func TestPostLog(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client @@ -484,7 +484,7 @@ func TestPostLog(t *testing.T) { } func TestUploadLicenseFile(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client @@ -502,7 +502,7 @@ func TestUploadLicenseFile(t *testing.T) { } func TestRemoveLicenseFile(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client @@ -520,7 +520,7 @@ func TestRemoveLicenseFile(t *testing.T) { } func TestGetAnalyticsOld(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client @@ -593,7 +593,7 @@ func TestGetAnalyticsOld(t *testing.T) { } func TestS3TestConnection(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client @@ -672,7 +672,7 @@ func TestRedirectLocation(t *testing.T) { mockBitlyLink := testServer.URL - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client enableLinkPreviews := *th.App.Config().ServiceSettings.EnableLinkPreviews diff --git a/api4/team_test.go b/api4/team_test.go index 8f1027cc5b6..45abe6d44cd 100644 --- a/api4/team_test.go +++ b/api4/team_test.go @@ -86,7 +86,7 @@ func TestCreateTeam(t *testing.T) { } func TestCreateTeamSanitization(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() // Non-admin users can create a team, but they become a team admin by doing so @@ -125,7 +125,7 @@ func TestCreateTeamSanitization(t *testing.T) { } func TestGetTeam(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client team := th.BasicTeam @@ -172,7 +172,7 @@ func TestGetTeam(t *testing.T) { } func TestGetTeamSanitization(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() team, resp := th.Client.CreateTeam(&model.Team{ @@ -215,7 +215,7 @@ func TestGetTeamSanitization(t *testing.T) { } func TestGetTeamUnread(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client @@ -249,7 +249,7 @@ func TestGetTeamUnread(t *testing.T) { } func TestUpdateTeam(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client @@ -344,7 +344,7 @@ func TestUpdateTeam(t *testing.T) { } func TestUpdateTeamSanitization(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() team, resp := th.Client.CreateTeam(&model.Team{ @@ -376,7 +376,7 @@ func TestUpdateTeamSanitization(t *testing.T) { } func TestPatchTeam(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client @@ -439,7 +439,7 @@ func TestPatchTeam(t *testing.T) { } func TestPatchTeamSanitization(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() team, resp := th.Client.CreateTeam(&model.Team{ @@ -471,7 +471,7 @@ func TestPatchTeamSanitization(t *testing.T) { } func TestSoftDeleteTeam(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client @@ -513,7 +513,7 @@ func TestSoftDeleteTeam(t *testing.T) { } func TestPermanentDeleteTeam(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client @@ -554,7 +554,7 @@ func TestPermanentDeleteTeam(t *testing.T) { } func TestGetAllTeams(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client @@ -627,7 +627,7 @@ func TestGetAllTeams(t *testing.T) { } func TestGetAllTeamsSanitization(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() team, resp := th.Client.CreateTeam(&model.Team{ @@ -692,7 +692,7 @@ func TestGetAllTeamsSanitization(t *testing.T) { } func TestGetTeamByName(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client team := th.BasicTeam @@ -739,7 +739,7 @@ func TestGetTeamByName(t *testing.T) { } func TestGetTeamByNameSanitization(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() team, resp := th.Client.CreateTeam(&model.Team{ @@ -782,7 +782,7 @@ func TestGetTeamByNameSanitization(t *testing.T) { } func TestSearchAllTeams(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client oTeam := th.BasicTeam @@ -864,7 +864,7 @@ func TestSearchAllTeams(t *testing.T) { } func TestSearchAllTeamsSanitization(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() team, resp := th.Client.CreateTeam(&model.Team{ @@ -940,7 +940,7 @@ func TestSearchAllTeamsSanitization(t *testing.T) { } func TestGetTeamsForUser(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client @@ -982,7 +982,7 @@ func TestGetTeamsForUser(t *testing.T) { } func TestGetTeamsForUserSanitization(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() team, resp := th.Client.CreateTeam(&model.Team{ @@ -1052,7 +1052,7 @@ func TestGetTeamsForUserSanitization(t *testing.T) { } func TestGetTeamMember(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client team := th.BasicTeam @@ -1089,7 +1089,7 @@ func TestGetTeamMember(t *testing.T) { } func TestGetTeamMembers(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client team := th.BasicTeam @@ -1154,7 +1154,7 @@ func TestGetTeamMembers(t *testing.T) { } func TestGetTeamMembersForUser(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client @@ -1230,7 +1230,7 @@ func TestGetTeamMembersByIds(t *testing.T) { } func TestAddTeamMember(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client team := th.BasicTeam @@ -1411,7 +1411,7 @@ func TestAddTeamMember(t *testing.T) { } func TestAddTeamMembers(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client team := th.BasicTeam @@ -1512,7 +1512,7 @@ func TestAddTeamMembers(t *testing.T) { } func TestRemoveTeamMember(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client @@ -1543,7 +1543,7 @@ func TestRemoveTeamMember(t *testing.T) { } func TestGetTeamStats(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client team := th.BasicTeam @@ -1598,7 +1598,7 @@ func TestGetTeamStats(t *testing.T) { } func TestUpdateTeamMemberRoles(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client SystemAdminClient := th.SystemAdminClient @@ -1676,7 +1676,7 @@ func TestUpdateTeamMemberRoles(t *testing.T) { } func TestUpdateTeamMemberSchemeRoles(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() SystemAdminClient := th.SystemAdminClient th.LoginBasic() @@ -1751,7 +1751,7 @@ func TestUpdateTeamMemberSchemeRoles(t *testing.T) { } func TestGetMyTeamsUnread(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client @@ -1782,7 +1782,7 @@ func TestGetMyTeamsUnread(t *testing.T) { } func TestTeamExists(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client team := th.BasicTeam @@ -1807,7 +1807,7 @@ func TestTeamExists(t *testing.T) { } func TestImportTeam(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() t.Run("ImportTeam", func(t *testing.T) { @@ -1886,7 +1886,7 @@ func TestImportTeam(t *testing.T) { } func TestInviteUsersToTeam(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() user1 := th.GenerateTestEmail() @@ -1996,7 +1996,7 @@ func TestInviteUsersToTeam(t *testing.T) { } func TestGetTeamInviteInfo(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client team := th.BasicTeam @@ -2024,7 +2024,7 @@ func TestGetTeamInviteInfo(t *testing.T) { } func TestSetTeamIcon(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client team := th.BasicTeam @@ -2087,7 +2087,7 @@ func TestSetTeamIcon(t *testing.T) { } func TestGetTeamIcon(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client team := th.BasicTeam @@ -2103,7 +2103,7 @@ func TestGetTeamIcon(t *testing.T) { } func TestRemoveTeamIcon(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client team := th.BasicTeam @@ -2140,7 +2140,7 @@ func TestRemoveTeamIcon(t *testing.T) { } func TestUpdateTeamScheme(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() th.App.SetLicense(model.NewTestLicense("")) diff --git a/api4/terms_of_service_test.go b/api4/terms_of_service_test.go index d8745e975b3..962cf12ccc7 100644 --- a/api4/terms_of_service_test.go +++ b/api4/terms_of_service_test.go @@ -36,7 +36,7 @@ func TestCreateTermsOfService(t *testing.T) { } func TestCreateTermsOfServiceAdminUser(t *testing.T) { - th := Setup().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.SystemAdminClient diff --git a/api4/user_test.go b/api4/user_test.go index bb5c782fd5b..bdfc9736a95 100644 --- a/api4/user_test.go +++ b/api4/user_test.go @@ -17,7 +17,7 @@ import ( ) func TestCreateUser(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client AdminClient := th.SystemAdminClient @@ -93,7 +93,7 @@ func TestCreateUser(t *testing.T) { } func TestCreateUserWithToken(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client @@ -232,7 +232,7 @@ func TestCreateUserWithToken(t *testing.T) { } func TestCreateUserWithInviteId(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client AdminClient := th.SystemAdminClient @@ -353,7 +353,7 @@ func TestGetMe(t *testing.T) { } func TestGetUser(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client @@ -424,7 +424,7 @@ func TestGetUser(t *testing.T) { } func TestGetUserByUsername(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client @@ -492,7 +492,7 @@ func TestGetUserByUsername(t *testing.T) { } func TestGetUserByEmail(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client @@ -557,7 +557,7 @@ func TestGetUserByEmail(t *testing.T) { } func TestSearchUsers(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client @@ -747,7 +747,7 @@ func findUserInList(id string, users []*model.User) bool { } func TestAutocompleteUsers(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client teamId := th.BasicTeam.Id @@ -880,7 +880,7 @@ func TestAutocompleteUsers(t *testing.T) { } func TestGetProfileImage(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client user := th.BasicUser @@ -984,7 +984,7 @@ func TestGetUsersByUsernames(t *testing.T) { } func TestGetTotalUsersStat(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client @@ -999,7 +999,7 @@ func TestGetTotalUsersStat(t *testing.T) { } func TestUpdateUser(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client @@ -1064,7 +1064,7 @@ func TestUpdateUser(t *testing.T) { } func TestPatchUser(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client @@ -1160,7 +1160,7 @@ func TestPatchUser(t *testing.T) { } func TestUpdateUserAuth(t *testing.T) { - th := Setup().InitSystemAdmin().InitBasic() + th := Setup().InitBasic() defer th.TearDown() Client := th.SystemAdminClient @@ -1222,7 +1222,7 @@ func TestUpdateUserAuth(t *testing.T) { } func TestDeleteUser(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client @@ -1254,7 +1254,7 @@ func TestDeleteUser(t *testing.T) { } func TestUpdateUserRoles(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client @@ -1309,7 +1309,7 @@ func assertWebsocketEventUserUpdatedWithEmail(t *testing.T, client *model.WebSoc func TestUpdateUserActive(t *testing.T) { t.Run("basic tests", func(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client @@ -1376,7 +1376,7 @@ func TestUpdateUserActive(t *testing.T) { }) t.Run("websocket events", func(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() SystemAdminClient := th.SystemAdminClient @@ -1535,7 +1535,7 @@ func TestGetRecentlyActiveUsersInTeam(t *testing.T) { } func TestGetUsersWithoutTeam(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client SystemAdminClient := th.SystemAdminClient @@ -1585,7 +1585,7 @@ func TestGetUsersWithoutTeam(t *testing.T) { } func TestGetUsersInTeam(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client teamId := th.BasicTeam.Id @@ -1631,7 +1631,7 @@ func TestGetUsersInTeam(t *testing.T) { } func TestGetUsersNotInTeam(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client teamId := th.BasicTeam.Id @@ -1641,27 +1641,22 @@ func TestGetUsersNotInTeam(t *testing.T) { for _, u := range rusers { CheckUserSanitization(t, u) } + require.Len(t, rusers, 1, "should be 1 user in total") rusers, resp = Client.GetUsersNotInTeam(teamId, 0, 60, resp.Etag) CheckEtag(t, rusers, resp) rusers, resp = Client.GetUsersNotInTeam(teamId, 0, 1, "") CheckNoError(t, resp) - if len(rusers) != 1 { - t.Fatal("should be 1 per page") - } + require.Len(t, rusers, 1, "should be 1 per page") rusers, resp = Client.GetUsersNotInTeam(teamId, 1, 1, "") CheckNoError(t, resp) - if len(rusers) != 1 { - t.Fatal("should be 1 per page") - } + require.Len(t, rusers, 0, "should be no users") rusers, resp = Client.GetUsersNotInTeam(teamId, 10000, 100, "") CheckNoError(t, resp) - if len(rusers) != 0 { - t.Fatal("should be no users") - } + require.Len(t, rusers, 0, "should be no users") Client.Logout() _, resp = Client.GetUsersNotInTeam(teamId, 0, 60, "") @@ -1677,7 +1672,7 @@ func TestGetUsersNotInTeam(t *testing.T) { } func TestGetUsersInChannel(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client channelId := th.BasicChannel.Id @@ -1720,7 +1715,7 @@ func TestGetUsersInChannel(t *testing.T) { } func TestGetUsersNotInChannel(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client teamId := th.BasicTeam.Id @@ -1761,7 +1756,7 @@ func TestGetUsersNotInChannel(t *testing.T) { } func TestUpdateUserMfa(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client @@ -1777,7 +1772,7 @@ func TestUpdateUserMfa(t *testing.T) { } func TestCheckUserMfa(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client @@ -1823,7 +1818,7 @@ func TestCheckUserMfa(t *testing.T) { } func TestGenerateMfaSecret(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client @@ -1856,7 +1851,7 @@ func TestGenerateMfaSecret(t *testing.T) { } func TestUpdateUserPassword(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client @@ -1925,6 +1920,7 @@ func TestUpdateUserPassword(t *testing.T) { /*func TestResetPassword(t *testing.T) { th := Setup().InitBasic() + defer th.TearDown() Client := th.Client Client.Logout() user := th.BasicUser @@ -2009,7 +2005,7 @@ func TestUpdateUserPassword(t *testing.T) { }*/ func TestGetSessions(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client @@ -2049,7 +2045,7 @@ func TestGetSessions(t *testing.T) { } func TestRevokeSessions(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client @@ -2122,8 +2118,6 @@ func TestRevokeAllSessions(t *testing.T) { _, resp := Client.RevokeAllSessions(th.BasicUser2.Id) CheckForbiddenStatus(t, resp) - th.InitSystemAdmin() - _, resp = Client.RevokeAllSessions("junk" + user.Id) CheckBadRequestStatus(t, resp) @@ -2187,7 +2181,7 @@ func TestAttachDeviceId(t *testing.T) { } func TestGetUserAudits(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client user := th.BasicUser @@ -2260,7 +2254,7 @@ func TestSendVerificationEmail(t *testing.T) { } func TestSetProfileImage(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client user := th.BasicUser @@ -2311,7 +2305,7 @@ func TestSetProfileImage(t *testing.T) { } func TestSetDefaultProfileImage(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client user := th.BasicUser @@ -2407,7 +2401,7 @@ func TestCBALogin(t *testing.T) { } func TestSwitchAccount(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client @@ -2535,7 +2529,7 @@ func TestSwitchAccount(t *testing.T) { } func TestCreateUserAccessToken(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client AdminClient := th.SystemAdminClient @@ -2616,7 +2610,7 @@ func TestCreateUserAccessToken(t *testing.T) { } func TestGetUserAccessToken(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client AdminClient := th.SystemAdminClient @@ -2700,7 +2694,7 @@ func TestGetUserAccessToken(t *testing.T) { } func TestSearchUserAccessToken(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client AdminClient := th.SystemAdminClient @@ -2746,7 +2740,7 @@ func TestSearchUserAccessToken(t *testing.T) { } func TestRevokeUserAccessToken(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client AdminClient := th.SystemAdminClient @@ -2790,7 +2784,7 @@ func TestRevokeUserAccessToken(t *testing.T) { } func TestDisableUserAccessToken(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client AdminClient := th.SystemAdminClient @@ -2834,7 +2828,7 @@ func TestDisableUserAccessToken(t *testing.T) { } func TestEnableUserAccessToken(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client @@ -2876,7 +2870,7 @@ func TestEnableUserAccessToken(t *testing.T) { } func TestUserAccessTokenInactiveUser(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client @@ -2899,7 +2893,7 @@ func TestUserAccessTokenInactiveUser(t *testing.T) { } func TestUserAccessTokenDisableConfig(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client @@ -3092,7 +3086,6 @@ func TestRegisterTermsOfServiceAction(t *testing.T) { } } - func TestGetUserTermsOfService(t *testing.T) { th := Setup().InitBasic() defer th.TearDown() diff --git a/api4/webhook_test.go b/api4/webhook_test.go index 78598f9dc77..8abb948615c 100644 --- a/api4/webhook_test.go +++ b/api4/webhook_test.go @@ -12,7 +12,7 @@ import ( ) func TestCreateIncomingWebhook(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client @@ -74,7 +74,7 @@ func TestCreateIncomingWebhook(t *testing.T) { } func TestGetIncomingWebhooks(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client @@ -153,7 +153,7 @@ func TestGetIncomingWebhooks(t *testing.T) { } func TestGetIncomingWebhook(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.SystemAdminClient @@ -192,7 +192,7 @@ func TestGetIncomingWebhook(t *testing.T) { } func TestDeleteIncomingWebhook(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.SystemAdminClient @@ -243,7 +243,7 @@ func TestDeleteIncomingWebhook(t *testing.T) { } func TestCreateOutgoingWebhook(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client @@ -293,7 +293,7 @@ func TestCreateOutgoingWebhook(t *testing.T) { } func TestGetOutgoingWebhooks(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client @@ -394,7 +394,7 @@ func TestGetOutgoingWebhooks(t *testing.T) { } func TestGetOutgoingWebhook(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client @@ -424,7 +424,7 @@ func TestGetOutgoingWebhook(t *testing.T) { } func TestUpdateIncomingHook(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client @@ -644,7 +644,7 @@ func TestUpdateIncomingHook(t *testing.T) { } func TestRegenOutgoingHookToken(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client @@ -676,7 +676,7 @@ func TestRegenOutgoingHookToken(t *testing.T) { } func TestUpdateOutgoingHook(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.Client @@ -839,7 +839,7 @@ func TestUpdateOutgoingHook(t *testing.T) { } func TestDeleteOutgoingHook(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() Client := th.SystemAdminClient diff --git a/app/apptestlib.go b/app/apptestlib.go index dcc1fa9419a..01dc6b30e12 100644 --- a/app/apptestlib.go +++ b/app/apptestlib.go @@ -67,6 +67,10 @@ func StopTestStore() { } func setupTestHelper(enterprise bool) *TestHelper { + if testStore != nil { + testStore.DropAllTables() + } + permConfig, err := os.Open(utils.FindConfigFile("config.json")) if err != nil { panic(err) @@ -148,8 +152,13 @@ func Setup() *TestHelper { } func (me *TestHelper) InitBasic() *TestHelper { + me.SystemAdminUser = me.CreateUser() + me.App.UpdateUserRoles(me.SystemAdminUser.Id, model.SYSTEM_USER_ROLE_ID+" "+model.SYSTEM_ADMIN_ROLE_ID, false) + me.SystemAdminUser, _ = me.App.GetUser(me.SystemAdminUser.Id) + me.BasicTeam = me.CreateTeam() me.BasicUser = me.CreateUser() + me.LinkUserToTeam(me.BasicUser, me.BasicTeam) me.BasicUser2 = me.CreateUser() me.LinkUserToTeam(me.BasicUser2, me.BasicTeam) @@ -159,14 +168,6 @@ func (me *TestHelper) InitBasic() *TestHelper { return me } -func (me *TestHelper) InitSystemAdmin() *TestHelper { - me.SystemAdminUser = me.CreateUser() - me.App.UpdateUserRoles(me.SystemAdminUser.Id, model.SYSTEM_USER_ROLE_ID+" "+model.SYSTEM_ADMIN_ROLE_ID, false) - me.SystemAdminUser, _ = me.App.GetUser(me.SystemAdminUser.Id) - - return me -} - func (me *TestHelper) MockHTTPService(handler http.Handler) *TestHelper { me.MockedHTTPService = testutils.MakeMockedHTTPService(handler) me.App.HTTPService = me.MockedHTTPService diff --git a/app/channel_test.go b/app/channel_test.go index 9214b27b890..9acf8a709d4 100644 --- a/app/channel_test.go +++ b/app/channel_test.go @@ -713,7 +713,7 @@ func TestRenameChannel(t *testing.T) { } func TestGetChannelMembersTimezones(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() userRequestorId := "" diff --git a/app/web_conn_test.go b/app/web_conn_test.go index c378c837051..d49c8e9d1f8 100644 --- a/app/web_conn_test.go +++ b/app/web_conn_test.go @@ -14,7 +14,7 @@ import ( ) func TestWebConnShouldSendEvent(t *testing.T) { - th := Setup().InitBasic().InitSystemAdmin() + th := Setup().InitBasic() defer th.TearDown() session, err := th.App.CreateSession(&model.Session{UserId: th.BasicUser.Id, Roles: th.BasicUser.GetRawRoles()}) diff --git a/cmd/mattermost/commands/command_test.go b/cmd/mattermost/commands/command_test.go index bc6c7304ecf..5830c474d39 100644 --- a/cmd/mattermost/commands/command_test.go +++ b/cmd/mattermost/commands/command_test.go @@ -16,7 +16,6 @@ import ( func TestCreateCommand(t *testing.T) { th := api4.Setup().InitBasic() - th.InitSystemAdmin() defer th.TearDown() team := th.BasicTeam adminUser := th.TeamAdminUser diff --git a/cmd/mattermost/commands/plugin_test.go b/cmd/mattermost/commands/plugin_test.go index 0438235835e..9712ba0e575 100644 --- a/cmd/mattermost/commands/plugin_test.go +++ b/cmd/mattermost/commands/plugin_test.go @@ -15,7 +15,7 @@ func TestPlugin(t *testing.T) { os.MkdirAll("./test-plugins", os.ModePerm) os.MkdirAll("./test-client-plugins", os.ModePerm) - th := api4.Setup().InitBasic().InitSystemAdmin() + th := api4.Setup().InitBasic() defer th.TearDown() path, _ := utils.FindDir("tests") diff --git a/cmd/mattermost/commands/team_test.go b/cmd/mattermost/commands/team_test.go index 16ebb5a0906..b7bbd090a38 100644 --- a/cmd/mattermost/commands/team_test.go +++ b/cmd/mattermost/commands/team_test.go @@ -12,7 +12,7 @@ import ( ) func TestCreateTeam(t *testing.T) { - th := api4.Setup().InitSystemAdmin() + th := api4.Setup().InitBasic() defer th.TearDown() id := model.NewId() @@ -29,7 +29,7 @@ func TestCreateTeam(t *testing.T) { } func TestJoinTeam(t *testing.T) { - th := api4.Setup().InitSystemAdmin().InitBasic() + th := api4.Setup().InitBasic() defer th.TearDown() CheckCommand(t, "team", "add", th.BasicTeam.Name, th.BasicUser.Email) diff --git a/cmd/mattermost/commands/user_test.go b/cmd/mattermost/commands/user_test.go index 088893602f7..80582c652b1 100644 --- a/cmd/mattermost/commands/user_test.go +++ b/cmd/mattermost/commands/user_test.go @@ -12,7 +12,7 @@ import ( ) func TestCreateUserWithTeam(t *testing.T) { - th := api4.Setup().InitBasic().InitSystemAdmin() + th := api4.Setup().InitBasic() defer th.TearDown() id := model.NewId() diff --git a/cmd/mattermost/commands/webhook_test.go b/cmd/mattermost/commands/webhook_test.go index fc4bf122814..d849a187b02 100644 --- a/cmd/mattermost/commands/webhook_test.go +++ b/cmd/mattermost/commands/webhook_test.go @@ -15,7 +15,7 @@ import ( ) func TestListWebhooks(t *testing.T) { - th := api4.Setup().InitBasic().InitSystemAdmin() + th := api4.Setup().InitBasic() defer th.TearDown() adminClient := th.SystemAdminClient @@ -54,7 +54,7 @@ func TestListWebhooks(t *testing.T) { } func TestCreateIncomingWebhook(t *testing.T) { - th := api4.Setup().InitBasic().InitSystemAdmin() + th := api4.Setup().InitBasic() defer th.TearDown() th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableIncomingWebhooks = true }) @@ -98,7 +98,7 @@ func TestCreateIncomingWebhook(t *testing.T) { } func TestModifyIncomingWebhook(t *testing.T) { - th := api4.Setup().InitBasic().InitSystemAdmin() + th := api4.Setup().InitBasic() defer th.TearDown() th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableIncomingWebhooks = true }) @@ -153,7 +153,7 @@ func TestModifyIncomingWebhook(t *testing.T) { } func TestCreateOutgoingWebhook(t *testing.T) { - th := api4.Setup().InitBasic().InitSystemAdmin() + th := api4.Setup().InitBasic() defer th.TearDown() th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableIncomingWebhooks = true }) diff --git a/migrations/migrationstestlib.go b/migrations/migrationstestlib.go index 0d9aeb3e319..d07973ca5b1 100644 --- a/migrations/migrationstestlib.go +++ b/migrations/migrationstestlib.go @@ -61,6 +61,10 @@ func StopTestStore() { } func setupTestHelper(enterprise bool) *TestHelper { + if testStore != nil { + testStore.DropAllTables() + } + permConfig, err := os.Open(utils.FindConfigFile("config.json")) if err != nil { panic(err) @@ -129,6 +133,10 @@ func Setup() *TestHelper { } func (me *TestHelper) InitBasic() *TestHelper { + me.SystemAdminUser = me.CreateUser() + me.App.UpdateUserRoles(me.SystemAdminUser.Id, model.SYSTEM_USER_ROLE_ID+" "+model.SYSTEM_ADMIN_ROLE_ID, false) + me.SystemAdminUser, _ = me.App.GetUser(me.SystemAdminUser.Id) + me.BasicTeam = me.CreateTeam() me.BasicUser = me.CreateUser() me.LinkUserToTeam(me.BasicUser, me.BasicTeam) @@ -140,14 +148,6 @@ func (me *TestHelper) InitBasic() *TestHelper { return me } -func (me *TestHelper) InitSystemAdmin() *TestHelper { - me.SystemAdminUser = me.CreateUser() - me.App.UpdateUserRoles(me.SystemAdminUser.Id, model.SYSTEM_USER_ROLE_ID+" "+model.SYSTEM_ADMIN_ROLE_ID, false) - me.SystemAdminUser, _ = me.App.GetUser(me.SystemAdminUser.Id) - - return me -} - func (me *TestHelper) MakeEmail() string { return "success_" + model.NewId() + "@simulator.amazonses.com" } diff --git a/store/layered_store.go b/store/layered_store.go index f69f55a7ebb..639e60001f6 100644 --- a/store/layered_store.go +++ b/store/layered_store.go @@ -198,6 +198,7 @@ func (s *LayeredStore) UnlockFromMaster() { } func (s *LayeredStore) DropAllTables() { + defer s.LocalCacheLayer.Invalidate() s.DatabaseLayer.DropAllTables() } diff --git a/store/local_cache_supplier.go b/store/local_cache_supplier.go index 417ffc89253..a27aa12af19 100644 --- a/store/local_cache_supplier.go +++ b/store/local_cache_supplier.go @@ -111,3 +111,9 @@ func (s *LocalCacheSupplier) doClearCacheCluster(cache utils.ObjectCache) { s.cluster.SendClusterMessage(msg) } } + +func (s *LocalCacheSupplier) Invalidate() { + s.doClearCacheCluster(s.reactionCache) + s.doClearCacheCluster(s.roleCache) + s.doClearCacheCluster(s.schemeCache) +} From cae7798d76fcfe1292140568960d57aa8edd0080 Mon Sep 17 00:00:00 2001 From: Carlos Tadeu Panato Junior Date: Wed, 21 Nov 2018 11:36:02 +0100 Subject: [PATCH 05/10] add CreateDirectChannel plugin api (#9848) --- app/plugin_api.go | 19 +++++++++++++++++++ app/plugin_api_test.go | 18 ++++++++++++++++++ plugin/api.go | 5 +++++ plugin/client_rpc_generated.go | 30 ++++++++++++++++++++++++++++++ plugin/plugintest/api.go | 25 +++++++++++++++++++++++++ 5 files changed, 97 insertions(+) diff --git a/app/plugin_api.go b/app/plugin_api.go index d6b601332e1..8a3f73fdf48 100644 --- a/app/plugin_api.go +++ b/app/plugin_api.go @@ -523,6 +523,25 @@ func (api *PluginAPI) RemoveTeamIcon(teamId string) *model.AppError { return nil } +func (api *PluginAPI) CreateDirectChannel(userId1 string, userId2 string) (*model.Channel, *model.AppError) { + _, err := api.app.GetUser(userId1) + if err != nil { + return nil, err + } + + _, err = api.app.GetUser(userId2) + if err != nil { + return nil, err + } + + dm, err := api.app.CreateDirectChannel(userId1, userId2) + if err != nil { + return nil, err + } + + return dm, nil +} + // Plugin Section func (api *PluginAPI) GetPlugins() ([]*model.Manifest, *model.AppError) { diff --git a/app/plugin_api_test.go b/app/plugin_api_test.go index e17dda9763c..24766f511e0 100644 --- a/app/plugin_api_test.go +++ b/app/plugin_api_test.go @@ -509,3 +509,21 @@ func TestPluginAPIRemoveTeamIcon(t *testing.T) { err = api.RemoveTeamIcon(th.BasicTeam.Id) require.Nil(t, err) } + +func TestPluginAPICreateDirectChannel(t *testing.T) { + th := Setup().InitBasic() + defer th.TearDown() + api := th.SetupPluginAPI() + + dm1, err := api.CreateDirectChannel(th.BasicUser.Id, th.BasicUser2.Id) + require.Nil(t, err) + require.NotEmpty(t, dm1) + + dm2, err := api.CreateDirectChannel(th.BasicUser.Id, th.BasicUser.Id) + require.Nil(t, err) + require.NotEmpty(t, dm2) + + dm3, err := api.CreateDirectChannel(th.BasicUser.Id, model.NewId()) + require.NotNil(t, err) + require.Empty(t, dm3) +} diff --git a/plugin/api.go b/plugin/api.go index 93f73ff08db..f2884862537 100644 --- a/plugin/api.go +++ b/plugin/api.go @@ -52,6 +52,11 @@ type API interface { // CreateUser creates a user. CreateUser(user *model.User) (*model.User, *model.AppError) + // CreateDirectChannel creates a Direct channel. + // + // Minimum server version: 5.6 + CreateDirectChannel(userId1 string, userId2 string) (*model.Channel, *model.AppError) + // DeleteUser deletes a user. DeleteUser(userId string) *model.AppError diff --git a/plugin/client_rpc_generated.go b/plugin/client_rpc_generated.go index a3520748454..7bb1e02c273 100644 --- a/plugin/client_rpc_generated.go +++ b/plugin/client_rpc_generated.go @@ -767,6 +767,36 @@ func (s *apiRPCServer) CreateUser(args *Z_CreateUserArgs, returns *Z_CreateUserR return nil } +type Z_CreateDirectChannelArgs struct { + A string + B string +} + +type Z_CreateDirectChannelReturns struct { + A *model.Channel + B *model.AppError +} + +func (g *apiRPCClient) CreateDirectChannel(userId1 string, userId2 string) (*model.Channel, *model.AppError) { + _args := &Z_CreateDirectChannelArgs{userId1, userId2} + _returns := &Z_CreateDirectChannelReturns{} + if err := g.client.Call("Plugin.CreateDirectChannel", _args, _returns); err != nil { + log.Printf("RPC call to CreateDirectChannel API failed: %s", err.Error()) + } + return _returns.A, _returns.B +} + +func (s *apiRPCServer) CreateDirectChannel(args *Z_CreateDirectChannelArgs, returns *Z_CreateDirectChannelReturns) error { + if hook, ok := s.impl.(interface { + CreateDirectChannel(userId1 string, userId2 string) (*model.Channel, *model.AppError) + }); ok { + returns.A, returns.B = hook.CreateDirectChannel(args.A, args.B) + } else { + return encodableError(fmt.Errorf("API CreateDirectChannel called but not implemented.")) + } + return nil +} + type Z_DeleteUserArgs struct { A string } diff --git a/plugin/plugintest/api.go b/plugin/plugintest/api.go index 5abde3308db..2f5b48beb7a 100644 --- a/plugin/plugintest/api.go +++ b/plugin/plugintest/api.go @@ -112,6 +112,31 @@ func (_m *API) CreateChannel(channel *model.Channel) (*model.Channel, *model.App return r0, r1 } +// CreateDirectChannel provides a mock function with given fields: userId1, userId2 +func (_m *API) CreateDirectChannel(userId1 string, userId2 string) (*model.Channel, *model.AppError) { + ret := _m.Called(userId1, userId2) + + var r0 *model.Channel + if rf, ok := ret.Get(0).(func(string, string) *model.Channel); ok { + r0 = rf(userId1, userId2) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*model.Channel) + } + } + + var r1 *model.AppError + if rf, ok := ret.Get(1).(func(string, string) *model.AppError); ok { + r1 = rf(userId1, userId2) + } else { + if ret.Get(1) != nil { + r1 = ret.Get(1).(*model.AppError) + } + } + + return r0, r1 +} + // CreatePost provides a mock function with given fields: post func (_m *API) CreatePost(post *model.Post) (*model.Post, *model.AppError) { ret := _m.Called(post) From 1271908182718b4c2a47e896e3b42c392296b3ce Mon Sep 17 00:00:00 2001 From: Yusuke Nemoto Date: Thu, 22 Nov 2018 11:10:59 +0900 Subject: [PATCH 06/10] Block to override post_type if already set (#9859) --- model/slack_attachment.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/model/slack_attachment.go b/model/slack_attachment.go index 827bf35b394..273def87676 100644 --- a/model/slack_attachment.go +++ b/model/slack_attachment.go @@ -64,7 +64,9 @@ func StringifySlackFieldValue(a []*SlackAttachment) []*SlackAttachment { // This method only parses and processes the attachments, // all else should be set in the post which is passed func ParseSlackAttachment(post *Post, attachments []*SlackAttachment) { - post.Type = POST_SLACK_ATTACHMENT + if post.Type == "" { + post.Type = POST_SLACK_ATTACHMENT + } for _, attachment := range attachments { attachment.Text = ParseSlackLinksToMarkdown(attachment.Text) From f8ffd68060dc572c0d73c91b5702435bc2d432a5 Mon Sep 17 00:00:00 2001 From: Jesse Hallam Date: Thu, 22 Nov 2018 04:53:44 -0500 Subject: [PATCH 07/10] Webhub race condition (#9863) * fix webconn close semantics Avoid race conditions in WebConn on shutdown by closing channels to guarantee all readers are notified. Wrap this with sync.Once to avoid closing the channel more than once. * web_hub_test.go * webhub: fix race condition on shutdown Ensure that if the webhub shuts down in the process of sending, the caller unblocks given that the webhub will no longer consume incoming events. * panic if app shutdown takes >30 seconds * simplify WebConn::Pump channel semantics too --- api4/apitestlib.go | 18 +++++++++++++++++- app/apptestlib.go | 19 ++++++++++++++++++- app/web_conn.go | 20 +++++++++++++------- app/web_hub.go | 22 +++++++++++++++++----- app/web_hub_test.go | 43 +++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 108 insertions(+), 14 deletions(-) diff --git a/api4/apitestlib.go b/api4/apitestlib.go index 0a843dfab53..ec047d5a68c 100644 --- a/api4/apitestlib.go +++ b/api4/apitestlib.go @@ -179,10 +179,26 @@ func SetupConfig(updateConfig func(cfg *model.Config)) *TestHelper { return setupTestHelper(false, updateConfig) } +func (me *TestHelper) ShutdownApp() { + done := make(chan bool) + go func() { + me.App.Shutdown() + close(done) + }() + + select { + case <-done: + case <-time.After(30 * time.Second): + // panic instead of t.Fatal to terminate all tests in this package, otherwise the + // still running App could spuriously fail subsequent tests. + panic("failed to shutdown App within 30 seconds") + } +} + func (me *TestHelper) TearDown() { utils.DisableDebugLogForTest() - me.App.Shutdown() + me.ShutdownApp() os.Remove(me.tempConfigPath) utils.EnableDebugLogForTest() diff --git a/app/apptestlib.go b/app/apptestlib.go index 01dc6b30e12..81569c90fd7 100644 --- a/app/apptestlib.go +++ b/app/apptestlib.go @@ -391,8 +391,25 @@ func (me *TestHelper) CreateScheme() (*model.Scheme, []*model.Role) { return scheme, roles } +func (me *TestHelper) ShutdownApp() { + done := make(chan bool) + go func() { + me.App.Shutdown() + close(done) + }() + + select { + case <-done: + case <-time.After(30 * time.Second): + // panic instead of t.Fatal to terminate all tests in this package, otherwise the + // still running App could spuriously fail subsequent tests. + panic("failed to shutdown App within 30 seconds") + } +} + func (me *TestHelper) TearDown() { - me.App.Shutdown() + me.ShutdownApp() + os.Remove(me.tempConfigPath) if err := recover(); err != nil { StopTestStore() diff --git a/app/web_conn.go b/app/web_conn.go index 7eea5d3bb35..49e85f62dae 100644 --- a/app/web_conn.go +++ b/app/web_conn.go @@ -5,6 +5,7 @@ package app import ( "fmt" + "sync" "sync/atomic" "time" @@ -39,6 +40,7 @@ type WebConn struct { AllChannelMembers map[string]string LastAllChannelMembersTime int64 Sequence int64 + closeOnce sync.Once endWritePump chan struct{} pumpFinished chan struct{} } @@ -59,8 +61,8 @@ func (a *App) NewWebConn(ws *websocket.Conn, session model.Session, t goi18n.Tra UserId: session.UserId, T: t, Locale: locale, - endWritePump: make(chan struct{}, 2), - pumpFinished: make(chan struct{}, 1), + endWritePump: make(chan struct{}), + pumpFinished: make(chan struct{}), } wc.SetSession(&session) @@ -72,7 +74,9 @@ func (a *App) NewWebConn(ws *websocket.Conn, session model.Session, t goi18n.Tra func (wc *WebConn) Close() { wc.WebSocket.Close() - wc.endWritePump <- struct{}{} + wc.closeOnce.Do(func() { + close(wc.endWritePump) + }) <-wc.pumpFinished } @@ -105,16 +109,18 @@ func (c *WebConn) SetSession(v *model.Session) { } func (c *WebConn) Pump() { - ch := make(chan struct{}, 1) + ch := make(chan struct{}) go func() { c.writePump() - ch <- struct{}{} + close(ch) }() c.readPump() - c.endWritePump <- struct{}{} + c.closeOnce.Do(func() { + close(c.endWritePump) + }) <-ch c.App.HubUnregister(c) - c.pumpFinished <- struct{}{} + close(c.pumpFinished) } func (c *WebConn) readPump() { diff --git a/app/web_hub.go b/app/web_hub.go index f65bec931de..84275763627 100644 --- a/app/web_hub.go +++ b/app/web_hub.go @@ -346,7 +346,10 @@ func (a *App) UpdateWebConnUserActivity(session model.Session, activityAt int64) } func (h *Hub) Register(webConn *WebConn) { - h.register <- webConn + select { + case h.register <- webConn: + case <-h.didStop: + } if webConn.IsAuthenticated() { webConn.SendHello() @@ -356,22 +359,31 @@ func (h *Hub) Register(webConn *WebConn) { func (h *Hub) Unregister(webConn *WebConn) { select { case h.unregister <- webConn: - case <-h.stop: + case <-h.didStop: } } func (h *Hub) Broadcast(message *model.WebSocketEvent) { if h != nil && h.broadcast != nil && message != nil { - h.broadcast <- message + select { + case h.broadcast <- message: + case <-h.didStop: + } } } func (h *Hub) InvalidateUser(userId string) { - h.invalidateUser <- userId + select { + case h.invalidateUser <- userId: + case <-h.didStop: + } } func (h *Hub) UpdateActivity(userId, sessionToken string, activityAt int64) { - h.activity <- &WebConnActivityMessage{UserId: userId, SessionToken: sessionToken, ActivityAt: activityAt} + select { + case h.activity <- &WebConnActivityMessage{UserId: userId, SessionToken: sessionToken, ActivityAt: activityAt}: + case <-h.didStop: + } } func getGoroutineId() int { diff --git a/app/web_hub_test.go b/app/web_hub_test.go index 8702acb21c1..83b58489a3a 100644 --- a/app/web_hub_test.go +++ b/app/web_hub_test.go @@ -5,6 +5,7 @@ import ( "net/http" "net/http/httptest" "testing" + "time" "github.com/gorilla/websocket" goi18n "github.com/nicksnyder/go-i18n/i18n" @@ -60,3 +61,45 @@ func TestHubStopWithMultipleConnections(t *testing.T) { defer wc2.Close() defer wc3.Close() } + +// TestHubStopRaceCondition verifies that attempts to use the hub after it has shutdown does not +// block the caller indefinitely. +func TestHubStopRaceCondition(t *testing.T) { + th := Setup().InitBasic() + defer th.TearDown() + + s := httptest.NewServer(http.HandlerFunc(dummyWebsocketHandler(t))) + + th.App.HubStart() + wc1 := registerDummyWebConn(t, th.App, s.Listener.Addr(), th.BasicUser.Id) + defer wc1.Close() + + hub := th.App.Srv.Hubs[0] + th.App.HubStop() + time.Sleep(5 * time.Second) + + done := make(chan bool) + go func() { + wc4 := registerDummyWebConn(t, th.App, s.Listener.Addr(), th.BasicUser.Id) + wc5 := registerDummyWebConn(t, th.App, s.Listener.Addr(), th.BasicUser.Id) + hub.Register(wc4) + hub.Register(wc5) + + hub.UpdateActivity("userId", "sessionToken", 0) + + for i := 0; i <= BROADCAST_QUEUE_SIZE; i++ { + hub.Broadcast(&model.WebSocketEvent{}) + } + + hub.InvalidateUser("userId") + hub.Unregister(wc4) + hub.Unregister(wc5) + close(done) + }() + + select { + case <-done: + case <-time.After(15 * time.Second): + t.Fatalf("hub call did not return within 15 seconds after stop") + } +} From ffd92d5d48824a37af3bdcf3951b6a430b725f6e Mon Sep 17 00:00:00 2001 From: Hanzei <16541325+hanzei@users.noreply.github.com> Date: Thu, 22 Nov 2018 11:03:52 +0100 Subject: [PATCH 08/10] GH-9846: Migrate to idiomatic error handling in model/client4.go (#9851) * Migrate to idiomatic error handling in model/client4.go * Changes as requested * Add documentation for some methods --- model/client4.go | 2666 +++++++++++++++++++++++----------------------- 1 file changed, 1352 insertions(+), 1314 deletions(-) diff --git a/model/client4.go b/model/client4.go index 67a24ccc24e..9e1856ec558 100644 --- a/model/client4.go +++ b/model/client4.go @@ -63,15 +63,14 @@ type Client4 struct { func closeBody(r *http.Response) { if r.Body != nil { - ioutil.ReadAll(r.Body) - r.Body.Close() + _, _ = ioutil.ReadAll(r.Body) + _ = r.Body.Close() } } // Must is a convenience function used for testing. func (c *Client4) Must(result interface{}, resp *Response) interface{} { if resp.Error != nil { - time.Sleep(time.Second) panic(resp.Error) } @@ -450,22 +449,26 @@ func (c *Client4) doApiRequestReader(method, url string, data io.Reader, etag st } if c.HttpHeader != nil && len(c.HttpHeader) > 0 { - for k, v := range c.HttpHeader { rq.Header.Set(k, v) } } - if rp, err := c.HttpClient.Do(rq); err != nil || rp == nil { + rp, err := c.HttpClient.Do(rq) + if err != nil || rp == nil { return nil, NewAppError(url, "model.client.connecting.app_error", nil, err.Error(), 0) - } else if rp.StatusCode == 304 { - return rp, nil - } else if rp.StatusCode >= 300 { - defer closeBody(rp) - return rp, AppErrorFromJson(rp.Body) - } else { + } + + if rp.StatusCode == 304 { return rp, nil } + + if rp.StatusCode >= 300 { + defer closeBody(rp) + return rp, AppErrorFromJson(rp.Body) + } + + return rp, nil } func (c *Client4) DoUploadFile(url string, data []byte, contentType string) (*FileUploadResponse, *Response) { @@ -476,17 +479,17 @@ func (c *Client4) DoUploadFile(url string, data []byte, contentType string) (*Fi rq.Header.Set(HEADER_AUTH, c.AuthType+" "+c.AuthToken) } - if rp, err := c.HttpClient.Do(rq); err != nil || rp == nil { + rp, err := c.HttpClient.Do(rq) + if err != nil || rp == nil { return nil, BuildErrorResponse(rp, NewAppError(url, "model.client.connecting.app_error", nil, err.Error(), 0)) - } else { - defer closeBody(rp) - - if rp.StatusCode >= 300 { - return nil, BuildErrorResponse(rp, AppErrorFromJson(rp.Body)) - } else { - return FileUploadResponseFromJson(rp.Body), BuildResponse(rp) - } } + defer closeBody(rp) + + if rp.StatusCode >= 300 { + return nil, BuildErrorResponse(rp, AppErrorFromJson(rp.Body)) + } + + return FileUploadResponseFromJson(rp.Body), BuildResponse(rp) } func (c *Client4) DoEmojiUploadFile(url string, data []byte, contentType string) (*Emoji, *Response) { @@ -497,17 +500,17 @@ func (c *Client4) DoEmojiUploadFile(url string, data []byte, contentType string) rq.Header.Set(HEADER_AUTH, c.AuthType+" "+c.AuthToken) } - if rp, err := c.HttpClient.Do(rq); err != nil || rp == nil { + rp, err := c.HttpClient.Do(rq) + if err != nil || rp == nil { return nil, BuildErrorResponse(rp, NewAppError(url, "model.client.connecting.app_error", nil, err.Error(), 0)) - } else { - defer closeBody(rp) - - if rp.StatusCode >= 300 { - return nil, BuildErrorResponse(rp, AppErrorFromJson(rp.Body)) - } else { - return EmojiFromJson(rp.Body), BuildResponse(rp) - } } + defer closeBody(rp) + + if rp.StatusCode >= 300 { + return nil, BuildErrorResponse(rp, AppErrorFromJson(rp.Body)) + } + + return EmojiFromJson(rp.Body), BuildResponse(rp) } func (c *Client4) DoUploadImportTeam(url string, data []byte, contentType string) (map[string]string, *Response) { @@ -518,17 +521,17 @@ func (c *Client4) DoUploadImportTeam(url string, data []byte, contentType string rq.Header.Set(HEADER_AUTH, c.AuthType+" "+c.AuthToken) } - if rp, err := c.HttpClient.Do(rq); err != nil || rp == nil { + rp, err := c.HttpClient.Do(rq) + if err != nil || rp == nil { return nil, BuildErrorResponse(rp, NewAppError(url, "model.client.connecting.app_error", nil, err.Error(), 0)) - } else { - defer closeBody(rp) - - if rp.StatusCode >= 300 { - return nil, BuildErrorResponse(rp, AppErrorFromJson(rp.Body)) - } else { - return MapFromJson(rp.Body), BuildResponse(rp) - } } + defer closeBody(rp) + + if rp.StatusCode >= 300 { + return nil, BuildErrorResponse(rp, AppErrorFromJson(rp.Body)) + } + + return MapFromJson(rp.Body), BuildResponse(rp) } // CheckStatusOK is a convenience function for checking the standard OK response @@ -584,156 +587,155 @@ func (c *Client4) LoginWithDevice(loginId string, password string, deviceId stri } func (c *Client4) login(m map[string]string) (*User, *Response) { - if r, err := c.DoApiPost("/users/login", MapToJson(m)); err != nil { + r, err := c.DoApiPost("/users/login", MapToJson(m)) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - c.AuthToken = r.Header.Get(HEADER_TOKEN) - c.AuthType = HEADER_BEARER - defer closeBody(r) - return UserFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + c.AuthToken = r.Header.Get(HEADER_TOKEN) + c.AuthType = HEADER_BEARER + return UserFromJson(r.Body), BuildResponse(r) } // Logout terminates the current user's session. func (c *Client4) Logout() (bool, *Response) { - if r, err := c.DoApiPost("/users/logout", ""); err != nil { + r, err := c.DoApiPost("/users/logout", "") + if err != nil { return false, BuildErrorResponse(r, err) - } else { - c.AuthToken = "" - c.AuthType = HEADER_BEARER - - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + c.AuthToken = "" + c.AuthType = HEADER_BEARER + return CheckStatusOK(r), BuildResponse(r) } // SwitchAccountType changes a user's login type from one type to another. func (c *Client4) SwitchAccountType(switchRequest *SwitchRequest) (string, *Response) { - if r, err := c.DoApiPost(c.GetUsersRoute()+"/login/switch", switchRequest.ToJson()); err != nil { + r, err := c.DoApiPost(c.GetUsersRoute()+"/login/switch", switchRequest.ToJson()) + if err != nil { return "", BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return MapFromJson(r.Body)["follow_link"], BuildResponse(r) } + defer closeBody(r) + return MapFromJson(r.Body)["follow_link"], BuildResponse(r) } // User Section // CreateUser creates a user in the system based on the provided user struct. func (c *Client4) CreateUser(user *User) (*User, *Response) { - if r, err := c.DoApiPost(c.GetUsersRoute(), user.ToJson()); err != nil { + r, err := c.DoApiPost(c.GetUsersRoute(), user.ToJson()) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return UserFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return UserFromJson(r.Body), BuildResponse(r) } // CreateUserWithToken creates a user in the system based on the provided tokenId. func (c *Client4) CreateUserWithToken(user *User, tokenId string) (*User, *Response) { - var query string - if tokenId != "" { - query = fmt.Sprintf("?t=%v", tokenId) - } else { + if tokenId == "" { err := NewAppError("MissingHashOrData", "api.user.create_user.missing_token.app_error", nil, "", http.StatusBadRequest) return nil, &Response{StatusCode: err.StatusCode, Error: err} } - if r, err := c.DoApiPost(c.GetUsersRoute()+query, user.ToJson()); err != nil { + + query := fmt.Sprintf("?t=%v", tokenId) + r, err := c.DoApiPost(c.GetUsersRoute()+query, user.ToJson()) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return UserFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + + return UserFromJson(r.Body), BuildResponse(r) } // CreateUserWithInviteId creates a user in the system based on the provided invited id. func (c *Client4) CreateUserWithInviteId(user *User, inviteId string) (*User, *Response) { - var query string - if inviteId != "" { - query = fmt.Sprintf("?iid=%v", url.QueryEscape(inviteId)) - } else { + if inviteId == "" { err := NewAppError("MissingInviteId", "api.user.create_user.missing_invite_id.app_error", nil, "", http.StatusBadRequest) return nil, &Response{StatusCode: err.StatusCode, Error: err} } - if r, err := c.DoApiPost(c.GetUsersRoute()+query, user.ToJson()); err != nil { + + query := fmt.Sprintf("?iid=%v", url.QueryEscape(inviteId)) + r, err := c.DoApiPost(c.GetUsersRoute()+query, user.ToJson()) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return UserFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + + return UserFromJson(r.Body), BuildResponse(r) } // GetMe returns the logged in user. func (c *Client4) GetMe(etag string) (*User, *Response) { - if r, err := c.DoApiGet(c.GetUserRoute(ME), etag); err != nil { + r, err := c.DoApiGet(c.GetUserRoute(ME), etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return UserFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return UserFromJson(r.Body), BuildResponse(r) } // GetUser returns a user based on the provided user id string. func (c *Client4) GetUser(userId, etag string) (*User, *Response) { - if r, err := c.DoApiGet(c.GetUserRoute(userId), etag); err != nil { + r, err := c.DoApiGet(c.GetUserRoute(userId), etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return UserFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return UserFromJson(r.Body), BuildResponse(r) } // GetUserByUsername returns a user based on the provided user name string. func (c *Client4) GetUserByUsername(userName, etag string) (*User, *Response) { - if r, err := c.DoApiGet(c.GetUserByUsernameRoute(userName), etag); err != nil { + r, err := c.DoApiGet(c.GetUserByUsernameRoute(userName), etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return UserFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return UserFromJson(r.Body), BuildResponse(r) } // GetUserByEmail returns a user based on the provided user email string. func (c *Client4) GetUserByEmail(email, etag string) (*User, *Response) { - if r, err := c.DoApiGet(c.GetUserByEmailRoute(email), etag); err != nil { + r, err := c.DoApiGet(c.GetUserByEmailRoute(email), etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return UserFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return UserFromJson(r.Body), BuildResponse(r) } // AutocompleteUsersInTeam returns the users on a team based on search term. func (c *Client4) AutocompleteUsersInTeam(teamId string, username string, limit int, etag string) (*UserAutocomplete, *Response) { query := fmt.Sprintf("?in_team=%v&name=%v&limit=%d", teamId, username, limit) - if r, err := c.DoApiGet(c.GetUsersRoute()+"/autocomplete"+query, etag); err != nil { + r, err := c.DoApiGet(c.GetUsersRoute()+"/autocomplete"+query, etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return UserAutocompleteFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return UserAutocompleteFromJson(r.Body), BuildResponse(r) } // AutocompleteUsersInChannel returns the users in a channel based on search term. func (c *Client4) AutocompleteUsersInChannel(teamId string, channelId string, username string, limit int, etag string) (*UserAutocomplete, *Response) { query := fmt.Sprintf("?in_team=%v&in_channel=%v&name=%v&limit=%d", teamId, channelId, username, limit) - if r, err := c.DoApiGet(c.GetUsersRoute()+"/autocomplete"+query, etag); err != nil { + r, err := c.DoApiGet(c.GetUsersRoute()+"/autocomplete"+query, etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return UserAutocompleteFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return UserAutocompleteFromJson(r.Body), BuildResponse(r) } // AutocompleteUsers returns the users in the system based on search term. func (c *Client4) AutocompleteUsers(username string, limit int, etag string) (*UserAutocomplete, *Response) { query := fmt.Sprintf("?name=%v&limit=%d", username, limit) - if r, err := c.DoApiGet(c.GetUsersRoute()+"/autocomplete"+query, etag); err != nil { + r, err := c.DoApiGet(c.GetUsersRoute()+"/autocomplete"+query, etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return UserAutocompleteFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return UserAutocompleteFromJson(r.Body), BuildResponse(r) } // GetDefaultProfileImage gets the default user's profile image. Must be logged in. @@ -754,176 +756,176 @@ func (c *Client4) GetDefaultProfileImage(userId string) ([]byte, *Response) { // GetProfileImage gets user's profile image. Must be logged in. func (c *Client4) GetProfileImage(userId, etag string) ([]byte, *Response) { - if r, err := c.DoApiGet(c.GetUserRoute(userId)+"/image", etag); err != nil { - return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - - if data, err := ioutil.ReadAll(r.Body); err != nil { - return nil, BuildErrorResponse(r, NewAppError("GetProfileImage", "model.client.read_file.app_error", nil, err.Error(), r.StatusCode)) - } else { - return data, BuildResponse(r) - } + r, appErr := c.DoApiGet(c.GetUserRoute(userId)+"/image", etag) + if appErr != nil { + return nil, BuildErrorResponse(r, appErr) } + defer closeBody(r) + + data, err := ioutil.ReadAll(r.Body) + if err != nil { + return nil, BuildErrorResponse(r, NewAppError("GetProfileImage", "model.client.read_file.app_error", nil, err.Error(), r.StatusCode)) + } + return data, BuildResponse(r) } // GetUsers returns a page of users on the system. Page counting starts at 0. func (c *Client4) GetUsers(page int, perPage int, etag string) ([]*User, *Response) { query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage) - if r, err := c.DoApiGet(c.GetUsersRoute()+query, etag); err != nil { + r, err := c.DoApiGet(c.GetUsersRoute()+query, etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return UserListFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return UserListFromJson(r.Body), BuildResponse(r) } // GetUsersInTeam returns a page of users on a team. Page counting starts at 0. func (c *Client4) GetUsersInTeam(teamId string, page int, perPage int, etag string) ([]*User, *Response) { query := fmt.Sprintf("?in_team=%v&page=%v&per_page=%v", teamId, page, perPage) - if r, err := c.DoApiGet(c.GetUsersRoute()+query, etag); err != nil { + r, err := c.DoApiGet(c.GetUsersRoute()+query, etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return UserListFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return UserListFromJson(r.Body), BuildResponse(r) } // GetNewUsersInTeam returns a page of users on a team. Page counting starts at 0. func (c *Client4) GetNewUsersInTeam(teamId string, page int, perPage int, etag string) ([]*User, *Response) { query := fmt.Sprintf("?sort=create_at&in_team=%v&page=%v&per_page=%v", teamId, page, perPage) - if r, err := c.DoApiGet(c.GetUsersRoute()+query, etag); err != nil { + r, err := c.DoApiGet(c.GetUsersRoute()+query, etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return UserListFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return UserListFromJson(r.Body), BuildResponse(r) } // GetRecentlyActiveUsersInTeam returns a page of users on a team. Page counting starts at 0. func (c *Client4) GetRecentlyActiveUsersInTeam(teamId string, page int, perPage int, etag string) ([]*User, *Response) { query := fmt.Sprintf("?sort=last_activity_at&in_team=%v&page=%v&per_page=%v", teamId, page, perPage) - if r, err := c.DoApiGet(c.GetUsersRoute()+query, etag); err != nil { + r, err := c.DoApiGet(c.GetUsersRoute()+query, etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return UserListFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return UserListFromJson(r.Body), BuildResponse(r) } // GetUsersNotInTeam returns a page of users who are not in a team. Page counting starts at 0. func (c *Client4) GetUsersNotInTeam(teamId string, page int, perPage int, etag string) ([]*User, *Response) { query := fmt.Sprintf("?not_in_team=%v&page=%v&per_page=%v", teamId, page, perPage) - if r, err := c.DoApiGet(c.GetUsersRoute()+query, etag); err != nil { + r, err := c.DoApiGet(c.GetUsersRoute()+query, etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return UserListFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return UserListFromJson(r.Body), BuildResponse(r) } // GetUsersInChannel returns a page of users in a channel. Page counting starts at 0. func (c *Client4) GetUsersInChannel(channelId string, page int, perPage int, etag string) ([]*User, *Response) { query := fmt.Sprintf("?in_channel=%v&page=%v&per_page=%v", channelId, page, perPage) - if r, err := c.DoApiGet(c.GetUsersRoute()+query, etag); err != nil { + r, err := c.DoApiGet(c.GetUsersRoute()+query, etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return UserListFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return UserListFromJson(r.Body), BuildResponse(r) } // GetUsersInChannelByStatus returns a page of users in a channel. Page counting starts at 0. Sorted by Status func (c *Client4) GetUsersInChannelByStatus(channelId string, page int, perPage int, etag string) ([]*User, *Response) { query := fmt.Sprintf("?in_channel=%v&page=%v&per_page=%v&sort=status", channelId, page, perPage) - if r, err := c.DoApiGet(c.GetUsersRoute()+query, etag); err != nil { + r, err := c.DoApiGet(c.GetUsersRoute()+query, etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return UserListFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return UserListFromJson(r.Body), BuildResponse(r) } // GetUsersNotInChannel returns a page of users not in a channel. Page counting starts at 0. func (c *Client4) GetUsersNotInChannel(teamId, channelId string, page int, perPage int, etag string) ([]*User, *Response) { query := fmt.Sprintf("?in_team=%v¬_in_channel=%v&page=%v&per_page=%v", teamId, channelId, page, perPage) - if r, err := c.DoApiGet(c.GetUsersRoute()+query, etag); err != nil { + r, err := c.DoApiGet(c.GetUsersRoute()+query, etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return UserListFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return UserListFromJson(r.Body), BuildResponse(r) } // GetUsersWithoutTeam returns a page of users on the system that aren't on any teams. Page counting starts at 0. func (c *Client4) GetUsersWithoutTeam(page int, perPage int, etag string) ([]*User, *Response) { query := fmt.Sprintf("?without_team=1&page=%v&per_page=%v", page, perPage) - if r, err := c.DoApiGet(c.GetUsersRoute()+query, etag); err != nil { + r, err := c.DoApiGet(c.GetUsersRoute()+query, etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return UserListFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return UserListFromJson(r.Body), BuildResponse(r) } // GetUsersByIds returns a list of users based on the provided user ids. func (c *Client4) GetUsersByIds(userIds []string) ([]*User, *Response) { - if r, err := c.DoApiPost(c.GetUsersRoute()+"/ids", ArrayToJson(userIds)); err != nil { + r, err := c.DoApiPost(c.GetUsersRoute()+"/ids", ArrayToJson(userIds)) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return UserListFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return UserListFromJson(r.Body), BuildResponse(r) } // GetUsersByUsernames returns a list of users based on the provided usernames. func (c *Client4) GetUsersByUsernames(usernames []string) ([]*User, *Response) { - if r, err := c.DoApiPost(c.GetUsersRoute()+"/usernames", ArrayToJson(usernames)); err != nil { + r, err := c.DoApiPost(c.GetUsersRoute()+"/usernames", ArrayToJson(usernames)) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return UserListFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return UserListFromJson(r.Body), BuildResponse(r) } // SearchUsers returns a list of users based on some search criteria. func (c *Client4) SearchUsers(search *UserSearch) ([]*User, *Response) { - if r, err := c.doApiPostBytes(c.GetUsersRoute()+"/search", search.ToJson()); err != nil { + r, err := c.doApiPostBytes(c.GetUsersRoute()+"/search", search.ToJson()) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return UserListFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return UserListFromJson(r.Body), BuildResponse(r) } // UpdateUser updates a user in the system based on the provided user struct. func (c *Client4) UpdateUser(user *User) (*User, *Response) { - if r, err := c.DoApiPut(c.GetUserRoute(user.Id), user.ToJson()); err != nil { + r, err := c.DoApiPut(c.GetUserRoute(user.Id), user.ToJson()) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return UserFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return UserFromJson(r.Body), BuildResponse(r) } // PatchUser partially updates a user in the system. Any missing fields are not updated. func (c *Client4) PatchUser(userId string, patch *UserPatch) (*User, *Response) { - if r, err := c.DoApiPut(c.GetUserRoute(userId)+"/patch", patch.ToJson()); err != nil { + r, err := c.DoApiPut(c.GetUserRoute(userId)+"/patch", patch.ToJson()) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return UserFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return UserFromJson(r.Body), BuildResponse(r) } // UpdateUserAuth updates a user AuthData (uthData, authService and password) in the system. func (c *Client4) UpdateUserAuth(userId string, userAuth *UserAuth) (*UserAuth, *Response) { - if r, err := c.DoApiPut(c.GetUserRoute(userId)+"/auth", userAuth.ToJson()); err != nil { + r, err := c.DoApiPut(c.GetUserRoute(userId)+"/auth", userAuth.ToJson()) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return UserAuthFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return UserAuthFromJson(r.Body), BuildResponse(r) } // UpdateUserMfa activates multi-factor authentication for a user if activate @@ -934,12 +936,12 @@ func (c *Client4) UpdateUserMfa(userId, code string, activate bool) (bool, *Resp requestBody["activate"] = activate requestBody["code"] = code - if r, err := c.DoApiPut(c.GetUserRoute(userId)+"/mfa", StringInterfaceToJson(requestBody)); err != nil { + r, err := c.DoApiPut(c.GetUserRoute(userId)+"/mfa", StringInterfaceToJson(requestBody)) + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } // CheckUserMfa checks whether a user has MFA active on their account or not based on the @@ -947,178 +949,178 @@ func (c *Client4) UpdateUserMfa(userId, code string, activate bool) (bool, *Resp func (c *Client4) CheckUserMfa(loginId string) (bool, *Response) { requestBody := make(map[string]interface{}) requestBody["login_id"] = loginId - - if r, err := c.DoApiPost(c.GetUsersRoute()+"/mfa", StringInterfaceToJson(requestBody)); err != nil { + r, err := c.DoApiPost(c.GetUsersRoute()+"/mfa", StringInterfaceToJson(requestBody)) + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - data := StringInterfaceFromJson(r.Body) - if mfaRequired, ok := data["mfa_required"].(bool); !ok { - return false, BuildResponse(r) - } else { - return mfaRequired, BuildResponse(r) - } } + defer closeBody(r) + + data := StringInterfaceFromJson(r.Body) + mfaRequired, ok := data["mfa_required"].(bool) + if !ok { + return false, BuildResponse(r) + } + return mfaRequired, BuildResponse(r) } // GenerateMfaSecret will generate a new MFA secret for a user and return it as a string and // as a base64 encoded image QR code. func (c *Client4) GenerateMfaSecret(userId string) (*MfaSecret, *Response) { - if r, err := c.DoApiPost(c.GetUserRoute(userId)+"/mfa/generate", ""); err != nil { + r, err := c.DoApiPost(c.GetUserRoute(userId)+"/mfa/generate", "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return MfaSecretFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return MfaSecretFromJson(r.Body), BuildResponse(r) } // UpdateUserPassword updates a user's password. Must be logged in as the user or be a system administrator. func (c *Client4) UpdateUserPassword(userId, currentPassword, newPassword string) (bool, *Response) { requestBody := map[string]string{"current_password": currentPassword, "new_password": newPassword} - if r, err := c.DoApiPut(c.GetUserRoute(userId)+"/password", MapToJson(requestBody)); err != nil { + r, err := c.DoApiPut(c.GetUserRoute(userId)+"/password", MapToJson(requestBody)) + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } // UpdateUserRoles updates a user's roles in the system. A user can have "system_user" and "system_admin" roles. func (c *Client4) UpdateUserRoles(userId, roles string) (bool, *Response) { requestBody := map[string]string{"roles": roles} - if r, err := c.DoApiPut(c.GetUserRoute(userId)+"/roles", MapToJson(requestBody)); err != nil { + r, err := c.DoApiPut(c.GetUserRoute(userId)+"/roles", MapToJson(requestBody)) + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } // UpdateUserActive updates status of a user whether active or not. func (c *Client4) UpdateUserActive(userId string, active bool) (bool, *Response) { requestBody := make(map[string]interface{}) requestBody["active"] = active - - if r, err := c.DoApiPut(c.GetUserRoute(userId)+"/active", StringInterfaceToJson(requestBody)); err != nil { + r, err := c.DoApiPut(c.GetUserRoute(userId)+"/active", StringInterfaceToJson(requestBody)) + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + + return CheckStatusOK(r), BuildResponse(r) } // DeleteUser deactivates a user in the system based on the provided user id string. func (c *Client4) DeleteUser(userId string) (bool, *Response) { - if r, err := c.DoApiDelete(c.GetUserRoute(userId)); err != nil { + r, err := c.DoApiDelete(c.GetUserRoute(userId)) + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } // SendPasswordResetEmail will send a link for password resetting to a user with the // provided email. func (c *Client4) SendPasswordResetEmail(email string) (bool, *Response) { requestBody := map[string]string{"email": email} - if r, err := c.DoApiPost(c.GetUsersRoute()+"/password/reset/send", MapToJson(requestBody)); err != nil { + r, err := c.DoApiPost(c.GetUsersRoute()+"/password/reset/send", MapToJson(requestBody)) + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } // ResetPassword uses a recovery code to update reset a user's password. func (c *Client4) ResetPassword(token, newPassword string) (bool, *Response) { requestBody := map[string]string{"token": token, "new_password": newPassword} - if r, err := c.DoApiPost(c.GetUsersRoute()+"/password/reset", MapToJson(requestBody)); err != nil { + r, err := c.DoApiPost(c.GetUsersRoute()+"/password/reset", MapToJson(requestBody)) + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } // GetSessions returns a list of sessions based on the provided user id string. func (c *Client4) GetSessions(userId, etag string) ([]*Session, *Response) { - if r, err := c.DoApiGet(c.GetUserRoute(userId)+"/sessions", etag); err != nil { + r, err := c.DoApiGet(c.GetUserRoute(userId)+"/sessions", etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return SessionsFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return SessionsFromJson(r.Body), BuildResponse(r) } // RevokeSession revokes a user session based on the provided user id and session id strings. func (c *Client4) RevokeSession(userId, sessionId string) (bool, *Response) { requestBody := map[string]string{"session_id": sessionId} - if r, err := c.DoApiPost(c.GetUserRoute(userId)+"/sessions/revoke", MapToJson(requestBody)); err != nil { + r, err := c.DoApiPost(c.GetUserRoute(userId)+"/sessions/revoke", MapToJson(requestBody)) + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } // RevokeAllSessions revokes all sessions for the provided user id string. func (c *Client4) RevokeAllSessions(userId string) (bool, *Response) { - if r, err := c.DoApiPost(c.GetUserRoute(userId)+"/sessions/revoke/all", ""); err != nil { + r, err := c.DoApiPost(c.GetUserRoute(userId)+"/sessions/revoke/all", "") + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } // AttachDeviceId attaches a mobile device ID to the current session. func (c *Client4) AttachDeviceId(deviceId string) (bool, *Response) { requestBody := map[string]string{"device_id": deviceId} - if r, err := c.DoApiPut(c.GetUsersRoute()+"/sessions/device", MapToJson(requestBody)); err != nil { + r, err := c.DoApiPut(c.GetUsersRoute()+"/sessions/device", MapToJson(requestBody)) + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } // GetTeamsUnreadForUser will return an array with TeamUnread objects that contain the amount // of unread messages and mentions the current user has for the teams it belongs to. // An optional team ID can be set to exclude that team from the results. Must be authenticated. func (c *Client4) GetTeamsUnreadForUser(userId, teamIdToExclude string) ([]*TeamUnread, *Response) { - optional := "" + var optional string if teamIdToExclude != "" { optional += fmt.Sprintf("?exclude_team=%s", url.QueryEscape(teamIdToExclude)) } - if r, err := c.DoApiGet(c.GetUserRoute(userId)+"/teams/unread"+optional, ""); err != nil { + r, err := c.DoApiGet(c.GetUserRoute(userId)+"/teams/unread"+optional, "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return TeamsUnreadFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return TeamsUnreadFromJson(r.Body), BuildResponse(r) } // GetUserAudits returns a list of audit based on the provided user id string. func (c *Client4) GetUserAudits(userId string, page int, perPage int, etag string) (Audits, *Response) { query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage) - if r, err := c.DoApiGet(c.GetUserRoute(userId)+"/audits"+query, etag); err != nil { + r, err := c.DoApiGet(c.GetUserRoute(userId)+"/audits"+query, etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return AuditsFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return AuditsFromJson(r.Body), BuildResponse(r) } // VerifyUserEmail will verify a user's email using the supplied token. func (c *Client4) VerifyUserEmail(token string) (bool, *Response) { requestBody := map[string]string{"token": token} - if r, err := c.DoApiPost(c.GetUsersRoute()+"/email/verify", MapToJson(requestBody)); err != nil { + r, err := c.DoApiPost(c.GetUsersRoute()+"/email/verify", MapToJson(requestBody)) + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } // SendVerificationEmail will send an email to the user with the provided email address, if @@ -1126,15 +1128,15 @@ func (c *Client4) VerifyUserEmail(token string) (bool, *Response) { // email address. func (c *Client4) SendVerificationEmail(email string) (bool, *Response) { requestBody := map[string]string{"email": email} - if r, err := c.DoApiPost(c.GetUsersRoute()+"/email/verify/send", MapToJson(requestBody)); err != nil { + r, err := c.DoApiPost(c.GetUsersRoute()+"/email/verify/send", MapToJson(requestBody)) + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } -// SetDefaultProfileImage resets the profile image to a default generated one +// SetDefaultProfileImage resets the profile image to a default generated one. func (c *Client4) SetDefaultProfileImage(userId string) (bool, *Response) { r, err := c.DoApiDelete(c.GetUserRoute(userId) + "/image") if err != nil { @@ -1143,18 +1145,21 @@ func (c *Client4) SetDefaultProfileImage(userId string) (bool, *Response) { return CheckStatusOK(r), BuildResponse(r) } -// SetProfileImage sets profile image of the user +// SetProfileImage sets profile image of the user. func (c *Client4) SetProfileImage(userId string, data []byte) (bool, *Response) { body := &bytes.Buffer{} writer := multipart.NewWriter(body) - if part, err := writer.CreateFormFile("image", "profile.png"); err != nil { - return false, &Response{Error: NewAppError("SetProfileImage", "model.client.set_profile_user.no_file.app_error", nil, err.Error(), http.StatusBadRequest)} - } else if _, err = io.Copy(part, bytes.NewBuffer(data)); err != nil { + part, err := writer.CreateFormFile("image", "profile.png") + if err != nil { return false, &Response{Error: NewAppError("SetProfileImage", "model.client.set_profile_user.no_file.app_error", nil, err.Error(), http.StatusBadRequest)} } - if err := writer.Close(); err != nil { + if _, err = io.Copy(part, bytes.NewBuffer(data)); err != nil { + return false, &Response{Error: NewAppError("SetProfileImage", "model.client.set_profile_user.no_file.app_error", nil, err.Error(), http.StatusBadRequest)} + } + + if err = writer.Close(); err != nil { return false, &Response{Error: NewAppError("SetProfileImage", "model.client.set_profile_user.writer.app_error", nil, err.Error(), http.StatusBadRequest)} } @@ -1165,18 +1170,18 @@ func (c *Client4) SetProfileImage(userId string, data []byte) (bool, *Response) rq.Header.Set(HEADER_AUTH, c.AuthType+" "+c.AuthToken) } - if rp, err := c.HttpClient.Do(rq); err != nil || rp == nil { + rp, err := c.HttpClient.Do(rq) + if err != nil || rp == nil { // set to http.StatusForbidden(403) return false, &Response{StatusCode: http.StatusForbidden, Error: NewAppError(c.GetUserRoute(userId)+"/image", "model.client.connecting.app_error", nil, err.Error(), 403)} - } else { - defer closeBody(rp) - - if rp.StatusCode >= 300 { - return false, BuildErrorResponse(rp, AppErrorFromJson(rp.Body)) - } else { - return CheckStatusOK(rp), BuildResponse(rp) - } } + defer closeBody(rp) + + if rp.StatusCode >= 300 { + return false, BuildErrorResponse(rp, AppErrorFromJson(rp.Body)) + } + + return CheckStatusOK(rp), BuildResponse(rp) } // CreateUserAccessToken will generate a user access token that can be used in place @@ -1185,12 +1190,12 @@ func (c *Client4) SetProfileImage(userId string, data []byte) (bool, *Response) // permission. A non-blank description is required. func (c *Client4) CreateUserAccessToken(userId, description string) (*UserAccessToken, *Response) { requestBody := map[string]string{"description": description} - if r, err := c.DoApiPost(c.GetUserRoute(userId)+"/tokens", MapToJson(requestBody)); err != nil { + r, err := c.DoApiPost(c.GetUserRoute(userId)+"/tokens", MapToJson(requestBody)) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return UserAccessTokenFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return UserAccessTokenFromJson(r.Body), BuildResponse(r) } // GetUserAccessTokens will get a page of access tokens' id, description, is_active @@ -1198,12 +1203,12 @@ func (c *Client4) CreateUserAccessToken(userId, description string) (*UserAccess // the 'manage_system' permission. func (c *Client4) GetUserAccessTokens(page int, perPage int) ([]*UserAccessToken, *Response) { query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage) - if r, err := c.DoApiGet(c.GetUserAccessTokensRoute()+query, ""); err != nil { + r, err := c.DoApiGet(c.GetUserAccessTokensRoute()+query, "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return UserAccessTokenListFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return UserAccessTokenListFromJson(r.Body), BuildResponse(r) } // GetUserAccessToken will get a user access tokens' id, description, is_active @@ -1211,12 +1216,12 @@ func (c *Client4) GetUserAccessTokens(page int, perPage int) ([]*UserAccessToken // Must have the 'read_user_access_token' permission and if getting for another // user, must have the 'edit_other_users' permission. func (c *Client4) GetUserAccessToken(tokenId string) (*UserAccessToken, *Response) { - if r, err := c.DoApiGet(c.GetUserAccessTokenRoute(tokenId), ""); err != nil { + r, err := c.DoApiGet(c.GetUserAccessTokenRoute(tokenId), "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return UserAccessTokenFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return UserAccessTokenFromJson(r.Body), BuildResponse(r) } // GetUserAccessTokensForUser will get a paged list of user access tokens showing id, @@ -1225,12 +1230,12 @@ func (c *Client4) GetUserAccessToken(tokenId string) (*UserAccessToken, *Respons // 'edit_other_users' permission. func (c *Client4) GetUserAccessTokensForUser(userId string, page, perPage int) ([]*UserAccessToken, *Response) { query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage) - if r, err := c.DoApiGet(c.GetUserRoute(userId)+"/tokens"+query, ""); err != nil { + r, err := c.DoApiGet(c.GetUserRoute(userId)+"/tokens"+query, "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return UserAccessTokenListFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return UserAccessTokenListFromJson(r.Body), BuildResponse(r) } // RevokeUserAccessToken will revoke a user access token by id. Must have the @@ -1238,22 +1243,22 @@ func (c *Client4) GetUserAccessTokensForUser(userId string, page, perPage int) ( // 'edit_other_users' permission. func (c *Client4) RevokeUserAccessToken(tokenId string) (bool, *Response) { requestBody := map[string]string{"token_id": tokenId} - if r, err := c.DoApiPost(c.GetUsersRoute()+"/tokens/revoke", MapToJson(requestBody)); err != nil { + r, err := c.DoApiPost(c.GetUsersRoute()+"/tokens/revoke", MapToJson(requestBody)) + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } // SearchUserAccessTokens returns user access tokens matching the provided search term. func (c *Client4) SearchUserAccessTokens(search *UserAccessTokenSearch) ([]*UserAccessToken, *Response) { - if r, err := c.DoApiPost(c.GetUsersRoute()+"/tokens/search", search.ToJson()); err != nil { + r, err := c.DoApiPost(c.GetUsersRoute()+"/tokens/search", search.ToJson()) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return UserAccessTokenListFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return UserAccessTokenListFromJson(r.Body), BuildResponse(r) } // DisableUserAccessToken will disable a user access token by id. Must have the @@ -1261,12 +1266,12 @@ func (c *Client4) SearchUserAccessTokens(search *UserAccessTokenSearch) ([]*User // 'edit_other_users' permission. func (c *Client4) DisableUserAccessToken(tokenId string) (bool, *Response) { requestBody := map[string]string{"token_id": tokenId} - if r, err := c.DoApiPost(c.GetUsersRoute()+"/tokens/disable", MapToJson(requestBody)); err != nil { + r, err := c.DoApiPost(c.GetUsersRoute()+"/tokens/disable", MapToJson(requestBody)) + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } // EnableUserAccessToken will enable a user access token by id. Must have the @@ -1274,202 +1279,201 @@ func (c *Client4) DisableUserAccessToken(tokenId string) (bool, *Response) { // 'edit_other_users' permission. func (c *Client4) EnableUserAccessToken(tokenId string) (bool, *Response) { requestBody := map[string]string{"token_id": tokenId} - if r, err := c.DoApiPost(c.GetUsersRoute()+"/tokens/enable", MapToJson(requestBody)); err != nil { + r, err := c.DoApiPost(c.GetUsersRoute()+"/tokens/enable", MapToJson(requestBody)) + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } // Team Section // CreateTeam creates a team in the system based on the provided team struct. func (c *Client4) CreateTeam(team *Team) (*Team, *Response) { - if r, err := c.DoApiPost(c.GetTeamsRoute(), team.ToJson()); err != nil { + r, err := c.DoApiPost(c.GetTeamsRoute(), team.ToJson()) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return TeamFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return TeamFromJson(r.Body), BuildResponse(r) } // GetTeam returns a team based on the provided team id string. func (c *Client4) GetTeam(teamId, etag string) (*Team, *Response) { - if r, err := c.DoApiGet(c.GetTeamRoute(teamId), etag); err != nil { + r, err := c.DoApiGet(c.GetTeamRoute(teamId), etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return TeamFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return TeamFromJson(r.Body), BuildResponse(r) } // GetAllTeams returns all teams based on permissions. func (c *Client4) GetAllTeams(etag string, page int, perPage int) ([]*Team, *Response) { query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage) - if r, err := c.DoApiGet(c.GetTeamsRoute()+query, etag); err != nil { + r, err := c.DoApiGet(c.GetTeamsRoute()+query, etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return TeamListFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return TeamListFromJson(r.Body), BuildResponse(r) } // GetTeamByName returns a team based on the provided team name string. func (c *Client4) GetTeamByName(name, etag string) (*Team, *Response) { - if r, err := c.DoApiGet(c.GetTeamByNameRoute(name), etag); err != nil { + r, err := c.DoApiGet(c.GetTeamByNameRoute(name), etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return TeamFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return TeamFromJson(r.Body), BuildResponse(r) } // SearchTeams returns teams matching the provided search term. func (c *Client4) SearchTeams(search *TeamSearch) ([]*Team, *Response) { - if r, err := c.DoApiPost(c.GetTeamsRoute()+"/search", search.ToJson()); err != nil { + r, err := c.DoApiPost(c.GetTeamsRoute()+"/search", search.ToJson()) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return TeamListFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return TeamListFromJson(r.Body), BuildResponse(r) } // TeamExists returns true or false if the team exist or not. func (c *Client4) TeamExists(name, etag string) (bool, *Response) { - if r, err := c.DoApiGet(c.GetTeamByNameRoute(name)+"/exists", etag); err != nil { + r, err := c.DoApiGet(c.GetTeamByNameRoute(name)+"/exists", etag) + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return MapBoolFromJson(r.Body)["exists"], BuildResponse(r) } + defer closeBody(r) + return MapBoolFromJson(r.Body)["exists"], BuildResponse(r) } // GetTeamsForUser returns a list of teams a user is on. Must be logged in as the user // or be a system administrator. func (c *Client4) GetTeamsForUser(userId, etag string) ([]*Team, *Response) { - if r, err := c.DoApiGet(c.GetUserRoute(userId)+"/teams", etag); err != nil { + r, err := c.DoApiGet(c.GetUserRoute(userId)+"/teams", etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return TeamListFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return TeamListFromJson(r.Body), BuildResponse(r) } // GetTeamMember returns a team member based on the provided team and user id strings. func (c *Client4) GetTeamMember(teamId, userId, etag string) (*TeamMember, *Response) { - if r, err := c.DoApiGet(c.GetTeamMemberRoute(teamId, userId), etag); err != nil { + r, err := c.DoApiGet(c.GetTeamMemberRoute(teamId, userId), etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return TeamMemberFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return TeamMemberFromJson(r.Body), BuildResponse(r) } // UpdateTeamMemberRoles will update the roles on a team for a user. func (c *Client4) UpdateTeamMemberRoles(teamId, userId, newRoles string) (bool, *Response) { requestBody := map[string]string{"roles": newRoles} - if r, err := c.DoApiPut(c.GetTeamMemberRoute(teamId, userId)+"/roles", MapToJson(requestBody)); err != nil { + r, err := c.DoApiPut(c.GetTeamMemberRoute(teamId, userId)+"/roles", MapToJson(requestBody)) + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } // UpdateTeamMemberSchemeRoles will update the scheme-derived roles on a team for a user. func (c *Client4) UpdateTeamMemberSchemeRoles(teamId string, userId string, schemeRoles *SchemeRoles) (bool, *Response) { - if r, err := c.DoApiPut(c.GetTeamMemberRoute(teamId, userId)+"/schemeRoles", schemeRoles.ToJson()); err != nil { + r, err := c.DoApiPut(c.GetTeamMemberRoute(teamId, userId)+"/schemeRoles", schemeRoles.ToJson()) + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } // UpdateTeam will update a team. func (c *Client4) UpdateTeam(team *Team) (*Team, *Response) { - if r, err := c.DoApiPut(c.GetTeamRoute(team.Id), team.ToJson()); err != nil { + r, err := c.DoApiPut(c.GetTeamRoute(team.Id), team.ToJson()) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return TeamFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return TeamFromJson(r.Body), BuildResponse(r) } // PatchTeam partially updates a team. Any missing fields are not updated. func (c *Client4) PatchTeam(teamId string, patch *TeamPatch) (*Team, *Response) { - if r, err := c.DoApiPut(c.GetTeamRoute(teamId)+"/patch", patch.ToJson()); err != nil { + r, err := c.DoApiPut(c.GetTeamRoute(teamId)+"/patch", patch.ToJson()) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return TeamFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return TeamFromJson(r.Body), BuildResponse(r) } // SoftDeleteTeam deletes the team softly (archive only, not permanent delete). func (c *Client4) SoftDeleteTeam(teamId string) (bool, *Response) { - if r, err := c.DoApiDelete(c.GetTeamRoute(teamId)); err != nil { + r, err := c.DoApiDelete(c.GetTeamRoute(teamId)) + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } // PermanentDeleteTeam deletes the team, should only be used when needed for -// compliance and the like +// compliance and the like. func (c *Client4) PermanentDeleteTeam(teamId string) (bool, *Response) { - if r, err := c.DoApiDelete(c.GetTeamRoute(teamId) + "?permanent=true"); err != nil { + r, err := c.DoApiDelete(c.GetTeamRoute(teamId) + "?permanent=true") + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } // GetTeamMembers returns team members based on the provided team id string. func (c *Client4) GetTeamMembers(teamId string, page int, perPage int, etag string) ([]*TeamMember, *Response) { query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage) - if r, err := c.DoApiGet(c.GetTeamMembersRoute(teamId)+query, etag); err != nil { + r, err := c.DoApiGet(c.GetTeamMembersRoute(teamId)+query, etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return TeamMembersFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return TeamMembersFromJson(r.Body), BuildResponse(r) } // GetTeamMembersForUser returns the team members for a user. func (c *Client4) GetTeamMembersForUser(userId string, etag string) ([]*TeamMember, *Response) { - if r, err := c.DoApiGet(c.GetUserRoute(userId)+"/teams/members", etag); err != nil { + r, err := c.DoApiGet(c.GetUserRoute(userId)+"/teams/members", etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return TeamMembersFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return TeamMembersFromJson(r.Body), BuildResponse(r) } // GetTeamMembersByIds will return an array of team members based on the // team id and a list of user ids provided. Must be authenticated. func (c *Client4) GetTeamMembersByIds(teamId string, userIds []string) ([]*TeamMember, *Response) { - if r, err := c.DoApiPost(fmt.Sprintf("/teams/%v/members/ids", teamId), ArrayToJson(userIds)); err != nil { + r, err := c.DoApiPost(fmt.Sprintf("/teams/%v/members/ids", teamId), ArrayToJson(userIds)) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return TeamMembersFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return TeamMembersFromJson(r.Body), BuildResponse(r) } // AddTeamMember adds user to a team and return a team member. func (c *Client4) AddTeamMember(teamId, userId string) (*TeamMember, *Response) { member := &TeamMember{TeamId: teamId, UserId: userId} - - if r, err := c.DoApiPost(c.GetTeamMembersRoute(teamId), member.ToJson()); err != nil { + r, err := c.DoApiPost(c.GetTeamMembersRoute(teamId), member.ToJson()) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return TeamMemberFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return TeamMemberFromJson(r.Body), BuildResponse(r) } // AddTeamMemberFromInvite adds a user to a team and return a team member using an invite id @@ -1485,12 +1489,12 @@ func (c *Client4) AddTeamMemberFromInvite(token, inviteId string) (*TeamMember, query += fmt.Sprintf("?token=%v", token) } - if r, err := c.DoApiPost(c.GetTeamsRoute()+"/members/invite"+query, ""); err != nil { + r, err := c.DoApiPost(c.GetTeamsRoute()+"/members/invite"+query, "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return TeamMemberFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return TeamMemberFromJson(r.Body), BuildResponse(r) } // AddTeamMembers adds a number of users to a team and returns the team members. @@ -1501,56 +1505,56 @@ func (c *Client4) AddTeamMembers(teamId string, userIds []string) ([]*TeamMember members = append(members, member) } - if r, err := c.DoApiPost(c.GetTeamMembersRoute(teamId)+"/batch", TeamMembersToJson(members)); err != nil { + r, err := c.DoApiPost(c.GetTeamMembersRoute(teamId)+"/batch", TeamMembersToJson(members)) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return TeamMembersFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return TeamMembersFromJson(r.Body), BuildResponse(r) } // RemoveTeamMember will remove a user from a team. func (c *Client4) RemoveTeamMember(teamId, userId string) (bool, *Response) { - if r, err := c.DoApiDelete(c.GetTeamMemberRoute(teamId, userId)); err != nil { + r, err := c.DoApiDelete(c.GetTeamMemberRoute(teamId, userId)) + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } // GetTeamStats returns a team stats based on the team id string. // Must be authenticated. func (c *Client4) GetTeamStats(teamId, etag string) (*TeamStats, *Response) { - if r, err := c.DoApiGet(c.GetTeamStatsRoute(teamId), etag); err != nil { + r, err := c.DoApiGet(c.GetTeamStatsRoute(teamId), etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return TeamStatsFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return TeamStatsFromJson(r.Body), BuildResponse(r) } // GetTotalUsersStats returns a total system user stats. // Must be authenticated. func (c *Client4) GetTotalUsersStats(etag string) (*UsersStats, *Response) { - if r, err := c.DoApiGet(c.GetTotalUsersStatsRoute(), etag); err != nil { + r, err := c.DoApiGet(c.GetTotalUsersStatsRoute(), etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return UsersStatsFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return UsersStatsFromJson(r.Body), BuildResponse(r) } // GetTeamUnread will return a TeamUnread object that contains the amount of // unread messages and mentions the user has for the specified team. // Must be authenticated. func (c *Client4) GetTeamUnread(teamId, userId string) (*TeamUnread, *Response) { - if r, err := c.DoApiGet(c.GetUserRoute(userId)+c.GetTeamRoute(teamId)+"/unread", ""); err != nil { + r, err := c.DoApiGet(c.GetUserRoute(userId)+c.GetTeamRoute(teamId)+"/unread", "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return TeamUnreadFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return TeamUnreadFromJson(r.Body), BuildResponse(r) } // ImportTeam will import an exported team from other app into a existing team. @@ -1558,21 +1562,30 @@ func (c *Client4) ImportTeam(data []byte, filesize int, importFrom, filename, te body := &bytes.Buffer{} writer := multipart.NewWriter(body) - if part, err := writer.CreateFormFile("file", filename); err != nil { - return nil, &Response{Error: NewAppError("UploadImportTeam", "model.client.upload_post_attachment.file.app_error", nil, err.Error(), http.StatusBadRequest)} - } else if _, err = io.Copy(part, bytes.NewBuffer(data)); err != nil { + part, err := writer.CreateFormFile("file", filename) + if err != nil { return nil, &Response{Error: NewAppError("UploadImportTeam", "model.client.upload_post_attachment.file.app_error", nil, err.Error(), http.StatusBadRequest)} } - if part, err := writer.CreateFormField("filesize"); err != nil { - return nil, &Response{Error: NewAppError("UploadImportTeam", "model.client.upload_post_attachment.file_size.app_error", nil, err.Error(), http.StatusBadRequest)} - } else if _, err = io.Copy(part, strings.NewReader(strconv.Itoa(filesize))); err != nil { + if _, err = io.Copy(part, bytes.NewBuffer(data)); err != nil { + return nil, &Response{Error: NewAppError("UploadImportTeam", "model.client.upload_post_attachment.file.app_error", nil, err.Error(), http.StatusBadRequest)} + } + + part, err = writer.CreateFormField("filesize") + if err != nil { return nil, &Response{Error: NewAppError("UploadImportTeam", "model.client.upload_post_attachment.file_size.app_error", nil, err.Error(), http.StatusBadRequest)} } - if part, err := writer.CreateFormField("importFrom"); err != nil { + if _, err = io.Copy(part, strings.NewReader(strconv.Itoa(filesize))); err != nil { + return nil, &Response{Error: NewAppError("UploadImportTeam", "model.client.upload_post_attachment.file_size.app_error", nil, err.Error(), http.StatusBadRequest)} + } + + part, err = writer.CreateFormField("importFrom") + if err != nil { return nil, &Response{Error: NewAppError("UploadImportTeam", "model.client.upload_post_attachment.import_from.app_error", nil, err.Error(), http.StatusBadRequest)} - } else if _, err = io.Copy(part, strings.NewReader(importFrom)); err != nil { + } + + if _, err := io.Copy(part, strings.NewReader(importFrom)); err != nil { return nil, &Response{Error: NewAppError("UploadImportTeam", "model.client.upload_post_attachment.import_from.app_error", nil, err.Error(), http.StatusBadRequest)} } @@ -1585,37 +1598,39 @@ func (c *Client4) ImportTeam(data []byte, filesize int, importFrom, filename, te // InviteUsersToTeam invite users by email to the team. func (c *Client4) InviteUsersToTeam(teamId string, userEmails []string) (bool, *Response) { - if r, err := c.DoApiPost(c.GetTeamRoute(teamId)+"/invite/email", ArrayToJson(userEmails)); err != nil { + r, err := c.DoApiPost(c.GetTeamRoute(teamId)+"/invite/email", ArrayToJson(userEmails)) + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } // GetTeamInviteInfo returns a team object from an invite id containing sanitized information. func (c *Client4) GetTeamInviteInfo(inviteId string) (*Team, *Response) { - if r, err := c.DoApiGet(c.GetTeamsRoute()+"/invite/"+inviteId, ""); err != nil { + r, err := c.DoApiGet(c.GetTeamsRoute()+"/invite/"+inviteId, "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return TeamFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return TeamFromJson(r.Body), BuildResponse(r) } -// SetTeamIcon sets team icon of the team +// SetTeamIcon sets team icon of the team. func (c *Client4) SetTeamIcon(teamId string, data []byte) (bool, *Response) { - body := &bytes.Buffer{} writer := multipart.NewWriter(body) - if part, err := writer.CreateFormFile("image", "teamIcon.png"); err != nil { - return false, &Response{Error: NewAppError("SetTeamIcon", "model.client.set_team_icon.no_file.app_error", nil, err.Error(), http.StatusBadRequest)} - } else if _, err = io.Copy(part, bytes.NewBuffer(data)); err != nil { + part, err := writer.CreateFormFile("image", "teamIcon.png") + if err != nil { return false, &Response{Error: NewAppError("SetTeamIcon", "model.client.set_team_icon.no_file.app_error", nil, err.Error(), http.StatusBadRequest)} } - if err := writer.Close(); err != nil { + if _, err = io.Copy(part, bytes.NewBuffer(data)); err != nil { + return false, &Response{Error: NewAppError("SetTeamIcon", "model.client.set_team_icon.no_file.app_error", nil, err.Error(), http.StatusBadRequest)} + } + + if err = writer.Close(); err != nil { return false, &Response{Error: NewAppError("SetTeamIcon", "model.client.set_team_icon.writer.app_error", nil, err.Error(), http.StatusBadRequest)} } @@ -1626,137 +1641,137 @@ func (c *Client4) SetTeamIcon(teamId string, data []byte) (bool, *Response) { rq.Header.Set(HEADER_AUTH, c.AuthType+" "+c.AuthToken) } - if rp, err := c.HttpClient.Do(rq); err != nil || rp == nil { + rp, err := c.HttpClient.Do(rq) + if err != nil || rp == nil { // set to http.StatusForbidden(403) return false, &Response{StatusCode: http.StatusForbidden, Error: NewAppError(c.GetTeamRoute(teamId)+"/image", "model.client.connecting.app_error", nil, err.Error(), 403)} - } else { - defer closeBody(rp) - - if rp.StatusCode >= 300 { - return false, BuildErrorResponse(rp, AppErrorFromJson(rp.Body)) - } else { - return CheckStatusOK(rp), BuildResponse(rp) - } } + defer closeBody(rp) + + if rp.StatusCode >= 300 { + return false, BuildErrorResponse(rp, AppErrorFromJson(rp.Body)) + } + + return CheckStatusOK(rp), BuildResponse(rp) } -// GetTeamIcon gets the team icon of the team +// GetTeamIcon gets the team icon of the team. func (c *Client4) GetTeamIcon(teamId, etag string) ([]byte, *Response) { - if r, err := c.DoApiGet(c.GetTeamRoute(teamId)+"/image", etag); err != nil { - return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - - if data, err := ioutil.ReadAll(r.Body); err != nil { - return nil, BuildErrorResponse(r, NewAppError("GetTeamIcon", "model.client.get_team_icon.app_error", nil, err.Error(), r.StatusCode)) - } else { - return data, BuildResponse(r) - } + r, appErr := c.DoApiGet(c.GetTeamRoute(teamId)+"/image", etag) + if appErr != nil { + return nil, BuildErrorResponse(r, appErr) } + defer closeBody(r) + + data, err := ioutil.ReadAll(r.Body) + if err != nil { + return nil, BuildErrorResponse(r, NewAppError("GetTeamIcon", "model.client.get_team_icon.app_error", nil, err.Error(), r.StatusCode)) + } + return data, BuildResponse(r) } // RemoveTeamIcon updates LastTeamIconUpdate to 0 which indicates team icon is removed. func (c *Client4) RemoveTeamIcon(teamId string) (bool, *Response) { - if r, err := c.DoApiDelete(c.GetTeamRoute(teamId) + "/image"); err != nil { + r, err := c.DoApiDelete(c.GetTeamRoute(teamId) + "/image") + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } // Channel Section // CreateChannel creates a channel based on the provided channel struct. func (c *Client4) CreateChannel(channel *Channel) (*Channel, *Response) { - if r, err := c.DoApiPost(c.GetChannelsRoute(), channel.ToJson()); err != nil { + r, err := c.DoApiPost(c.GetChannelsRoute(), channel.ToJson()) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return ChannelFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return ChannelFromJson(r.Body), BuildResponse(r) } -// UpdateChannel update a channel based on the provided channel struct. +// UpdateChannel updates a channel based on the provided channel struct. func (c *Client4) UpdateChannel(channel *Channel) (*Channel, *Response) { - if r, err := c.DoApiPut(c.GetChannelRoute(channel.Id), channel.ToJson()); err != nil { + r, err := c.DoApiPut(c.GetChannelRoute(channel.Id), channel.ToJson()) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return ChannelFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return ChannelFromJson(r.Body), BuildResponse(r) } // PatchChannel partially updates a channel. Any missing fields are not updated. func (c *Client4) PatchChannel(channelId string, patch *ChannelPatch) (*Channel, *Response) { - if r, err := c.DoApiPut(c.GetChannelRoute(channelId)+"/patch", patch.ToJson()); err != nil { + r, err := c.DoApiPut(c.GetChannelRoute(channelId)+"/patch", patch.ToJson()) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return ChannelFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return ChannelFromJson(r.Body), BuildResponse(r) } // ConvertChannelToPrivate converts public to private channel. func (c *Client4) ConvertChannelToPrivate(channelId string) (*Channel, *Response) { - if r, err := c.DoApiPost(c.GetChannelRoute(channelId)+"/convert", ""); err != nil { + r, err := c.DoApiPost(c.GetChannelRoute(channelId)+"/convert", "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return ChannelFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return ChannelFromJson(r.Body), BuildResponse(r) } // RestoreChannel restores a previously deleted channel. Any missing fields are not updated. func (c *Client4) RestoreChannel(channelId string) (*Channel, *Response) { - if r, err := c.DoApiPost(c.GetChannelRoute(channelId)+"/restore", ""); err != nil { + r, err := c.DoApiPost(c.GetChannelRoute(channelId)+"/restore", "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return ChannelFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return ChannelFromJson(r.Body), BuildResponse(r) } // CreateDirectChannel creates a direct message channel based on the two user // ids provided. func (c *Client4) CreateDirectChannel(userId1, userId2 string) (*Channel, *Response) { requestBody := []string{userId1, userId2} - if r, err := c.DoApiPost(c.GetChannelsRoute()+"/direct", ArrayToJson(requestBody)); err != nil { + r, err := c.DoApiPost(c.GetChannelsRoute()+"/direct", ArrayToJson(requestBody)) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return ChannelFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return ChannelFromJson(r.Body), BuildResponse(r) } -// CreateGroupChannel creates a group message channel based on userIds provided +// CreateGroupChannel creates a group message channel based on userIds provided. func (c *Client4) CreateGroupChannel(userIds []string) (*Channel, *Response) { - if r, err := c.DoApiPost(c.GetChannelsRoute()+"/group", ArrayToJson(userIds)); err != nil { + r, err := c.DoApiPost(c.GetChannelsRoute()+"/group", ArrayToJson(userIds)) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return ChannelFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return ChannelFromJson(r.Body), BuildResponse(r) } // GetChannel returns a channel based on the provided channel id string. func (c *Client4) GetChannel(channelId, etag string) (*Channel, *Response) { - if r, err := c.DoApiGet(c.GetChannelRoute(channelId), etag); err != nil { + r, err := c.DoApiGet(c.GetChannelRoute(channelId), etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return ChannelFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return ChannelFromJson(r.Body), BuildResponse(r) } // GetChannelStats returns statistics for a channel. func (c *Client4) GetChannelStats(channelId string, etag string) (*ChannelStats, *Response) { - if r, err := c.DoApiGet(c.GetChannelRoute(channelId)+"/stats", etag); err != nil { + r, err := c.DoApiGet(c.GetChannelRoute(channelId)+"/stats", etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return ChannelStatsFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return ChannelStatsFromJson(r.Body), BuildResponse(r) } // GetChannelMembersTimezones gets a list of timezones for a channel. @@ -1765,382 +1780,382 @@ func (c *Client4) GetChannelMembersTimezones(channelId string) ([]string, *Respo if err != nil { return nil, BuildErrorResponse(r, err) } - defer closeBody(r) return ArrayFromJson(r.Body), BuildResponse(r) } // GetPinnedPosts gets a list of pinned posts. func (c *Client4) GetPinnedPosts(channelId string, etag string) (*PostList, *Response) { - if r, err := c.DoApiGet(c.GetChannelRoute(channelId)+"/pinned", etag); err != nil { + r, err := c.DoApiGet(c.GetChannelRoute(channelId)+"/pinned", etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return PostListFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return PostListFromJson(r.Body), BuildResponse(r) } // GetPublicChannelsForTeam returns a list of public channels based on the provided team id string. func (c *Client4) GetPublicChannelsForTeam(teamId string, page int, perPage int, etag string) ([]*Channel, *Response) { query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage) - if r, err := c.DoApiGet(c.GetChannelsForTeamRoute(teamId)+query, etag); err != nil { + r, err := c.DoApiGet(c.GetChannelsForTeamRoute(teamId)+query, etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return ChannelSliceFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return ChannelSliceFromJson(r.Body), BuildResponse(r) } // GetDeletedChannelsForTeam returns a list of public channels based on the provided team id string. func (c *Client4) GetDeletedChannelsForTeam(teamId string, page int, perPage int, etag string) ([]*Channel, *Response) { query := fmt.Sprintf("/deleted?page=%v&per_page=%v", page, perPage) - if r, err := c.DoApiGet(c.GetChannelsForTeamRoute(teamId)+query, etag); err != nil { + r, err := c.DoApiGet(c.GetChannelsForTeamRoute(teamId)+query, etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return ChannelSliceFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return ChannelSliceFromJson(r.Body), BuildResponse(r) } -// GetPublicChannelsByIdsForTeam returns a list of public channels based on provided team id string +// GetPublicChannelsByIdsForTeam returns a list of public channels based on provided team id string. func (c *Client4) GetPublicChannelsByIdsForTeam(teamId string, channelIds []string) ([]*Channel, *Response) { - if r, err := c.DoApiPost(c.GetChannelsForTeamRoute(teamId)+"/ids", ArrayToJson(channelIds)); err != nil { + r, err := c.DoApiPost(c.GetChannelsForTeamRoute(teamId)+"/ids", ArrayToJson(channelIds)) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return ChannelSliceFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return ChannelSliceFromJson(r.Body), BuildResponse(r) } // GetChannelsForTeamForUser returns a list channels of on a team for a user. func (c *Client4) GetChannelsForTeamForUser(teamId, userId, etag string) ([]*Channel, *Response) { - if r, err := c.DoApiGet(c.GetUserRoute(userId)+c.GetTeamRoute(teamId)+"/channels", etag); err != nil { + r, err := c.DoApiGet(c.GetUserRoute(userId)+c.GetTeamRoute(teamId)+"/channels", etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return ChannelSliceFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return ChannelSliceFromJson(r.Body), BuildResponse(r) } // SearchChannels returns the channels on a team matching the provided search term. func (c *Client4) SearchChannels(teamId string, search *ChannelSearch) ([]*Channel, *Response) { - if r, err := c.DoApiPost(c.GetChannelsForTeamRoute(teamId)+"/search", search.ToJson()); err != nil { + r, err := c.DoApiPost(c.GetChannelsForTeamRoute(teamId)+"/search", search.ToJson()) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return ChannelSliceFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return ChannelSliceFromJson(r.Body), BuildResponse(r) } // DeleteChannel deletes channel based on the provided channel id string. func (c *Client4) DeleteChannel(channelId string) (bool, *Response) { - if r, err := c.DoApiDelete(c.GetChannelRoute(channelId)); err != nil { + r, err := c.DoApiDelete(c.GetChannelRoute(channelId)) + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } // GetChannelByName returns a channel based on the provided channel name and team id strings. func (c *Client4) GetChannelByName(channelName, teamId string, etag string) (*Channel, *Response) { - if r, err := c.DoApiGet(c.GetChannelByNameRoute(channelName, teamId), etag); err != nil { + r, err := c.DoApiGet(c.GetChannelByNameRoute(channelName, teamId), etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return ChannelFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return ChannelFromJson(r.Body), BuildResponse(r) } +// GetChannelByNameIncludeDeleted returns a channel based on the provided channel name and team id strings. Other then GetChannelByName it will also return deleted channels. func (c *Client4) GetChannelByNameIncludeDeleted(channelName, teamId string, etag string) (*Channel, *Response) { - if r, err := c.DoApiGet(c.GetChannelByNameRoute(channelName, teamId)+"?include_deleted=true", etag); err != nil { + r, err := c.DoApiGet(c.GetChannelByNameRoute(channelName, teamId)+"?include_deleted=true", etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return ChannelFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return ChannelFromJson(r.Body), BuildResponse(r) } // GetChannelByNameForTeamName returns a channel based on the provided channel name and team name strings. func (c *Client4) GetChannelByNameForTeamName(channelName, teamName string, etag string) (*Channel, *Response) { - if r, err := c.DoApiGet(c.GetChannelByNameForTeamNameRoute(channelName, teamName), etag); err != nil { + r, err := c.DoApiGet(c.GetChannelByNameForTeamNameRoute(channelName, teamName), etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return ChannelFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return ChannelFromJson(r.Body), BuildResponse(r) } +// GetChannelByNameForTeamNameIncludeDeleted returns a channel based on the provided channel name and team name strings. Other then GetChannelByNameForTeamName it will also return deleted channels. func (c *Client4) GetChannelByNameForTeamNameIncludeDeleted(channelName, teamName string, etag string) (*Channel, *Response) { - if r, err := c.DoApiGet(c.GetChannelByNameForTeamNameRoute(channelName, teamName)+"?include_deleted=true", etag); err != nil { + r, err := c.DoApiGet(c.GetChannelByNameForTeamNameRoute(channelName, teamName)+"?include_deleted=true", etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return ChannelFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return ChannelFromJson(r.Body), BuildResponse(r) } // GetChannelMembers gets a page of channel members. func (c *Client4) GetChannelMembers(channelId string, page, perPage int, etag string) (*ChannelMembers, *Response) { query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage) - if r, err := c.DoApiGet(c.GetChannelMembersRoute(channelId)+query, etag); err != nil { + r, err := c.DoApiGet(c.GetChannelMembersRoute(channelId)+query, etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return ChannelMembersFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return ChannelMembersFromJson(r.Body), BuildResponse(r) } // GetChannelMembersByIds gets the channel members in a channel for a list of user ids. func (c *Client4) GetChannelMembersByIds(channelId string, userIds []string) (*ChannelMembers, *Response) { - if r, err := c.DoApiPost(c.GetChannelMembersRoute(channelId)+"/ids", ArrayToJson(userIds)); err != nil { + r, err := c.DoApiPost(c.GetChannelMembersRoute(channelId)+"/ids", ArrayToJson(userIds)) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return ChannelMembersFromJson(r.Body), BuildResponse(r) - } + defer closeBody(r) + return ChannelMembersFromJson(r.Body), BuildResponse(r) } // GetChannelMember gets a channel member. func (c *Client4) GetChannelMember(channelId, userId, etag string) (*ChannelMember, *Response) { - if r, err := c.DoApiGet(c.GetChannelMemberRoute(channelId, userId), etag); err != nil { + r, err := c.DoApiGet(c.GetChannelMemberRoute(channelId, userId), etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return ChannelMemberFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return ChannelMemberFromJson(r.Body), BuildResponse(r) } // GetChannelMembersForUser gets all the channel members for a user on a team. func (c *Client4) GetChannelMembersForUser(userId, teamId, etag string) (*ChannelMembers, *Response) { - if r, err := c.DoApiGet(fmt.Sprintf(c.GetUserRoute(userId)+"/teams/%v/channels/members", teamId), etag); err != nil { + r, err := c.DoApiGet(fmt.Sprintf(c.GetUserRoute(userId)+"/teams/%v/channels/members", teamId), etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return ChannelMembersFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return ChannelMembersFromJson(r.Body), BuildResponse(r) } // ViewChannel performs a view action for a user. Synonymous with switching channels or marking channels as read by a user. func (c *Client4) ViewChannel(userId string, view *ChannelView) (*ChannelViewResponse, *Response) { url := fmt.Sprintf(c.GetChannelsRoute()+"/members/%v/view", userId) - if r, err := c.DoApiPost(url, view.ToJson()); err != nil { + r, err := c.DoApiPost(url, view.ToJson()) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return ChannelViewResponseFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return ChannelViewResponseFromJson(r.Body), BuildResponse(r) } // GetChannelUnread will return a ChannelUnread object that contains the number of // unread messages and mentions for a user. func (c *Client4) GetChannelUnread(channelId, userId string) (*ChannelUnread, *Response) { - if r, err := c.DoApiGet(c.GetUserRoute(userId)+c.GetChannelRoute(channelId)+"/unread", ""); err != nil { + r, err := c.DoApiGet(c.GetUserRoute(userId)+c.GetChannelRoute(channelId)+"/unread", "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return ChannelUnreadFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return ChannelUnreadFromJson(r.Body), BuildResponse(r) } // UpdateChannelRoles will update the roles on a channel for a user. func (c *Client4) UpdateChannelRoles(channelId, userId, roles string) (bool, *Response) { requestBody := map[string]string{"roles": roles} - if r, err := c.DoApiPut(c.GetChannelMemberRoute(channelId, userId)+"/roles", MapToJson(requestBody)); err != nil { + r, err := c.DoApiPut(c.GetChannelMemberRoute(channelId, userId)+"/roles", MapToJson(requestBody)) + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } // UpdateChannelMemberSchemeRoles will update the scheme-derived roles on a channel for a user. func (c *Client4) UpdateChannelMemberSchemeRoles(channelId string, userId string, schemeRoles *SchemeRoles) (bool, *Response) { - if r, err := c.DoApiPut(c.GetChannelMemberRoute(channelId, userId)+"/schemeRoles", schemeRoles.ToJson()); err != nil { + r, err := c.DoApiPut(c.GetChannelMemberRoute(channelId, userId)+"/schemeRoles", schemeRoles.ToJson()) + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } // UpdateChannelNotifyProps will update the notification properties on a channel for a user. func (c *Client4) UpdateChannelNotifyProps(channelId, userId string, props map[string]string) (bool, *Response) { - if r, err := c.DoApiPut(c.GetChannelMemberRoute(channelId, userId)+"/notify_props", MapToJson(props)); err != nil { + r, err := c.DoApiPut(c.GetChannelMemberRoute(channelId, userId)+"/notify_props", MapToJson(props)) + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } // AddChannelMember adds user to channel and return a channel member. func (c *Client4) AddChannelMember(channelId, userId string) (*ChannelMember, *Response) { requestBody := map[string]string{"user_id": userId} - if r, err := c.DoApiPost(c.GetChannelMembersRoute(channelId)+"", MapToJson(requestBody)); err != nil { + r, err := c.DoApiPost(c.GetChannelMembersRoute(channelId)+"", MapToJson(requestBody)) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return ChannelMemberFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return ChannelMemberFromJson(r.Body), BuildResponse(r) } // AddChannelMemberWithRootId adds user to channel and return a channel member. Post add to channel message has the postRootId. func (c *Client4) AddChannelMemberWithRootId(channelId, userId, postRootId string) (*ChannelMember, *Response) { requestBody := map[string]string{"user_id": userId, "post_root_id": postRootId} - if r, err := c.DoApiPost(c.GetChannelMembersRoute(channelId)+"", MapToJson(requestBody)); err != nil { + r, err := c.DoApiPost(c.GetChannelMembersRoute(channelId)+"", MapToJson(requestBody)) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return ChannelMemberFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return ChannelMemberFromJson(r.Body), BuildResponse(r) } // RemoveUserFromChannel will delete the channel member object for a user, effectively removing the user from a channel. func (c *Client4) RemoveUserFromChannel(channelId, userId string) (bool, *Response) { - if r, err := c.DoApiDelete(c.GetChannelMemberRoute(channelId, userId)); err != nil { + r, err := c.DoApiDelete(c.GetChannelMemberRoute(channelId, userId)) + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } -// AutocompleteChannelsForTeam will return an ordered list of channels autocomplete suggestions +// AutocompleteChannelsForTeam will return an ordered list of channels autocomplete suggestions. func (c *Client4) AutocompleteChannelsForTeam(teamId, name string) (*ChannelList, *Response) { query := fmt.Sprintf("?name=%v", name) - if r, err := c.DoApiGet(c.GetChannelsForTeamRoute(teamId)+"/autocomplete"+query, ""); err != nil { + r, err := c.DoApiGet(c.GetChannelsForTeamRoute(teamId)+"/autocomplete"+query, "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return ChannelListFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return ChannelListFromJson(r.Body), BuildResponse(r) } -// AutocompleteChannelsForTeamForSearch will return an ordered list of your channels autocomplete suggestions +// AutocompleteChannelsForTeamForSearch will return an ordered list of your channels autocomplete suggestions. func (c *Client4) AutocompleteChannelsForTeamForSearch(teamId, name string) (*ChannelList, *Response) { query := fmt.Sprintf("?name=%v", name) - if r, err := c.DoApiGet(c.GetChannelsForTeamRoute(teamId)+"/search_autocomplete"+query, ""); err != nil { + r, err := c.DoApiGet(c.GetChannelsForTeamRoute(teamId)+"/search_autocomplete"+query, "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return ChannelListFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return ChannelListFromJson(r.Body), BuildResponse(r) } // Post Section // CreatePost creates a post based on the provided post struct. func (c *Client4) CreatePost(post *Post) (*Post, *Response) { - if r, err := c.DoApiPost(c.GetPostsRoute(), post.ToUnsanitizedJson()); err != nil { + r, err := c.DoApiPost(c.GetPostsRoute(), post.ToUnsanitizedJson()) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return PostFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return PostFromJson(r.Body), BuildResponse(r) } -// CreatePostEphemeral creates a ephemeral post based on the provided post struct which is send to the given user id +// CreatePostEphemeral creates a ephemeral post based on the provided post struct which is send to the given user id. func (c *Client4) CreatePostEphemeral(post *PostEphemeral) (*Post, *Response) { - if r, err := c.DoApiPost(c.GetPostsEphemeralRoute(), post.ToUnsanitizedJson()); err != nil { + r, err := c.DoApiPost(c.GetPostsEphemeralRoute(), post.ToUnsanitizedJson()) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return PostFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return PostFromJson(r.Body), BuildResponse(r) } // UpdatePost updates a post based on the provided post struct. func (c *Client4) UpdatePost(postId string, post *Post) (*Post, *Response) { - if r, err := c.DoApiPut(c.GetPostRoute(postId), post.ToUnsanitizedJson()); err != nil { + r, err := c.DoApiPut(c.GetPostRoute(postId), post.ToUnsanitizedJson()) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return PostFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return PostFromJson(r.Body), BuildResponse(r) } // PatchPost partially updates a post. Any missing fields are not updated. func (c *Client4) PatchPost(postId string, patch *PostPatch) (*Post, *Response) { - if r, err := c.DoApiPut(c.GetPostRoute(postId)+"/patch", patch.ToJson()); err != nil { + r, err := c.DoApiPut(c.GetPostRoute(postId)+"/patch", patch.ToJson()) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return PostFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return PostFromJson(r.Body), BuildResponse(r) } // PinPost pin a post based on provided post id string. func (c *Client4) PinPost(postId string) (bool, *Response) { - if r, err := c.DoApiPost(c.GetPostRoute(postId)+"/pin", ""); err != nil { + r, err := c.DoApiPost(c.GetPostRoute(postId)+"/pin", "") + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } // UnpinPost unpin a post based on provided post id string. func (c *Client4) UnpinPost(postId string) (bool, *Response) { - if r, err := c.DoApiPost(c.GetPostRoute(postId)+"/unpin", ""); err != nil { + r, err := c.DoApiPost(c.GetPostRoute(postId)+"/unpin", "") + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } // GetPost gets a single post. func (c *Client4) GetPost(postId string, etag string) (*Post, *Response) { - if r, err := c.DoApiGet(c.GetPostRoute(postId), etag); err != nil { + r, err := c.DoApiGet(c.GetPostRoute(postId), etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return PostFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return PostFromJson(r.Body), BuildResponse(r) } // DeletePost deletes a post from the provided post id string. func (c *Client4) DeletePost(postId string) (bool, *Response) { - if r, err := c.DoApiDelete(c.GetPostRoute(postId)); err != nil { + r, err := c.DoApiDelete(c.GetPostRoute(postId)) + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } // GetPostThread gets a post with all the other posts in the same thread. func (c *Client4) GetPostThread(postId string, etag string) (*PostList, *Response) { - if r, err := c.DoApiGet(c.GetPostRoute(postId)+"/thread", etag); err != nil { + r, err := c.DoApiGet(c.GetPostRoute(postId)+"/thread", etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return PostListFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return PostListFromJson(r.Body), BuildResponse(r) } // GetPostsForChannel gets a page of posts with an array for ordering for a channel. func (c *Client4) GetPostsForChannel(channelId string, page, perPage int, etag string) (*PostList, *Response) { query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage) - if r, err := c.DoApiGet(c.GetChannelRoute(channelId)+"/posts"+query, etag); err != nil { + r, err := c.DoApiGet(c.GetChannelRoute(channelId)+"/posts"+query, etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return PostListFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return PostListFromJson(r.Body), BuildResponse(r) } // GetFlaggedPostsForUser returns flagged posts of a user based on user id string. func (c *Client4) GetFlaggedPostsForUser(userId string, page int, perPage int) (*PostList, *Response) { query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage) - if r, err := c.DoApiGet(c.GetUserRoute(userId)+"/posts/flagged"+query, ""); err != nil { + r, err := c.DoApiGet(c.GetUserRoute(userId)+"/posts/flagged"+query, "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return PostListFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return PostListFromJson(r.Body), BuildResponse(r) } // GetFlaggedPostsForUserInTeam returns flagged posts in team of a user based on user id string. @@ -2150,12 +2165,12 @@ func (c *Client4) GetFlaggedPostsForUserInTeam(userId string, teamId string, pag } query := fmt.Sprintf("?team_id=%v&page=%v&per_page=%v", teamId, page, perPage) - if r, err := c.DoApiGet(c.GetUserRoute(userId)+"/posts/flagged"+query, ""); err != nil { + r, err := c.DoApiGet(c.GetUserRoute(userId)+"/posts/flagged"+query, "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return PostListFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return PostListFromJson(r.Body), BuildResponse(r) } // GetFlaggedPostsForUserInChannel returns flagged posts in channel of a user based on user id string. @@ -2165,45 +2180,45 @@ func (c *Client4) GetFlaggedPostsForUserInChannel(userId string, channelId strin } query := fmt.Sprintf("?channel_id=%v&page=%v&per_page=%v", channelId, page, perPage) - if r, err := c.DoApiGet(c.GetUserRoute(userId)+"/posts/flagged"+query, ""); err != nil { + r, err := c.DoApiGet(c.GetUserRoute(userId)+"/posts/flagged"+query, "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return PostListFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return PostListFromJson(r.Body), BuildResponse(r) } // GetPostsSince gets posts created after a specified time as Unix time in milliseconds. func (c *Client4) GetPostsSince(channelId string, time int64) (*PostList, *Response) { query := fmt.Sprintf("?since=%v", time) - if r, err := c.DoApiGet(c.GetChannelRoute(channelId)+"/posts"+query, ""); err != nil { + r, err := c.DoApiGet(c.GetChannelRoute(channelId)+"/posts"+query, "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return PostListFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return PostListFromJson(r.Body), BuildResponse(r) } // GetPostsAfter gets a page of posts that were posted after the post provided. func (c *Client4) GetPostsAfter(channelId, postId string, page, perPage int, etag string) (*PostList, *Response) { query := fmt.Sprintf("?page=%v&per_page=%v&after=%v", page, perPage, postId) - if r, err := c.DoApiGet(c.GetChannelRoute(channelId)+"/posts"+query, etag); err != nil { + r, err := c.DoApiGet(c.GetChannelRoute(channelId)+"/posts"+query, etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return PostListFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return PostListFromJson(r.Body), BuildResponse(r) } // GetPostsBefore gets a page of posts that were posted before the post provided. func (c *Client4) GetPostsBefore(channelId, postId string, page, perPage int, etag string) (*PostList, *Response) { query := fmt.Sprintf("?page=%v&per_page=%v&before=%v", page, perPage, postId) - if r, err := c.DoApiGet(c.GetChannelRoute(channelId)+"/posts"+query, etag); err != nil { + r, err := c.DoApiGet(c.GetChannelRoute(channelId)+"/posts"+query, etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return PostListFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return PostListFromJson(r.Body), BuildResponse(r) } // SearchPosts returns any posts with matching terms string. @@ -2215,35 +2230,35 @@ func (c *Client4) SearchPosts(teamId string, terms string, isOrSearch bool) (*Po return c.SearchPostsWithParams(teamId, ¶ms) } -// SearchPosts returns any posts with matching terms string. +// SearchPostsWithParams returns any posts with matching terms string. func (c *Client4) SearchPostsWithParams(teamId string, params *SearchParameter) (*PostList, *Response) { - if r, err := c.DoApiPost(c.GetTeamRoute(teamId)+"/posts/search", params.SearchParameterToJson()); err != nil { + r, err := c.DoApiPost(c.GetTeamRoute(teamId)+"/posts/search", params.SearchParameterToJson()) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return PostListFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return PostListFromJson(r.Body), BuildResponse(r) } -// SearchPosts returns any posts with matching terms string, including. +// SearchPostsWithMatches returns any posts with matching terms string, including. func (c *Client4) SearchPostsWithMatches(teamId string, terms string, isOrSearch bool) (*PostSearchResults, *Response) { requestBody := map[string]interface{}{"terms": terms, "is_or_search": isOrSearch} - if r, err := c.DoApiPost(c.GetTeamRoute(teamId)+"/posts/search", StringInterfaceToJson(requestBody)); err != nil { + r, err := c.DoApiPost(c.GetTeamRoute(teamId)+"/posts/search", StringInterfaceToJson(requestBody)) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return PostSearchResultsFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return PostSearchResultsFromJson(r.Body), BuildResponse(r) } // DoPostAction performs a post action. func (c *Client4) DoPostAction(postId, actionId string) (bool, *Response) { - if r, err := c.DoApiPost(c.GetPostRoute(postId)+"/actions/"+actionId, ""); err != nil { + r, err := c.DoApiPost(c.GetPostRoute(postId)+"/actions/"+actionId, "") + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } // OpenInteractiveDialog sends a WebSocket event to a user's clients to @@ -2252,26 +2267,27 @@ func (c *Client4) DoPostAction(postId, actionId string) (bool, *Response) { // slash commands. func (c *Client4) OpenInteractiveDialog(request OpenDialogRequest) (bool, *Response) { b, _ := json.Marshal(request) - if r, err := c.DoApiPost("/actions/dialogs/open", string(b)); err != nil { + r, err := c.DoApiPost("/actions/dialogs/open", string(b)) + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } // SubmitInteractiveDialog will submit the provided dialog data to the integration // configured by the URL. Used with the interactive dialogs integration feature. func (c *Client4) SubmitInteractiveDialog(request SubmitDialogRequest) (*SubmitDialogResponse, *Response) { b, _ := json.Marshal(request) - if r, err := c.DoApiPost("/actions/dialogs/submit", string(b)); err != nil { + r, err := c.DoApiPost("/actions/dialogs/submit", string(b)) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - var resp SubmitDialogResponse - json.NewDecoder(r.Body).Decode(&resp) - return &resp, BuildResponse(r) } + defer closeBody(r) + + var resp SubmitDialogResponse + json.NewDecoder(r.Body).Decode(&resp) + return &resp, BuildResponse(r) } // File Section @@ -2282,15 +2298,21 @@ func (c *Client4) UploadFile(data []byte, channelId string, filename string) (*F body := &bytes.Buffer{} writer := multipart.NewWriter(body) - if part, err := writer.CreateFormFile("files", filename); err != nil { - return nil, &Response{Error: NewAppError("UploadPostAttachment", "model.client.upload_post_attachment.file.app_error", nil, err.Error(), http.StatusBadRequest)} - } else if _, err = io.Copy(part, bytes.NewBuffer(data)); err != nil { + part, err := writer.CreateFormFile("files", filename) + if err != nil { return nil, &Response{Error: NewAppError("UploadPostAttachment", "model.client.upload_post_attachment.file.app_error", nil, err.Error(), http.StatusBadRequest)} } - if part, err := writer.CreateFormField("channel_id"); err != nil { + if _, err = io.Copy(part, bytes.NewBuffer(data)); err != nil { + return nil, &Response{Error: NewAppError("UploadPostAttachment", "model.client.upload_post_attachment.file.app_error", nil, err.Error(), http.StatusBadRequest)} + } + + part, err = writer.CreateFormField("channel_id") + if err != nil { return nil, &Response{Error: NewAppError("UploadPostAttachment", "model.client.upload_post_attachment.channel_id.app_error", nil, err.Error(), http.StatusBadRequest)} - } else if _, err = io.Copy(part, strings.NewReader(channelId)); err != nil { + } + + if _, err := io.Copy(part, strings.NewReader(channelId)); err != nil { return nil, &Response{Error: NewAppError("UploadPostAttachment", "model.client.upload_post_attachment.channel_id.app_error", nil, err.Error(), http.StatusBadRequest)} } @@ -2309,242 +2331,242 @@ func (c *Client4) UploadFileAsRequestBody(data []byte, channelId string, filenam // GetFile gets the bytes for a file by id. func (c *Client4) GetFile(fileId string) ([]byte, *Response) { - if r, err := c.DoApiGet(c.GetFileRoute(fileId), ""); err != nil { - return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - - if data, err := ioutil.ReadAll(r.Body); err != nil { - return nil, BuildErrorResponse(r, NewAppError("GetFile", "model.client.read_file.app_error", nil, err.Error(), r.StatusCode)) - } else { - return data, BuildResponse(r) - } + r, appErr := c.DoApiGet(c.GetFileRoute(fileId), "") + if appErr != nil { + return nil, BuildErrorResponse(r, appErr) } + defer closeBody(r) + + data, err := ioutil.ReadAll(r.Body) + if err != nil { + return nil, BuildErrorResponse(r, NewAppError("GetFile", "model.client.read_file.app_error", nil, err.Error(), r.StatusCode)) + } + return data, BuildResponse(r) } -// DownloadFile gets the bytes for a file by id, optionally adding headers to force the browser to download it +// DownloadFile gets the bytes for a file by id, optionally adding headers to force the browser to download it. func (c *Client4) DownloadFile(fileId string, download bool) ([]byte, *Response) { - if r, err := c.DoApiGet(c.GetFileRoute(fileId)+fmt.Sprintf("?download=%v", download), ""); err != nil { - return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - - if data, err := ioutil.ReadAll(r.Body); err != nil { - return nil, BuildErrorResponse(r, NewAppError("DownloadFile", "model.client.read_file.app_error", nil, err.Error(), r.StatusCode)) - } else { - return data, BuildResponse(r) - } + r, appErr := c.DoApiGet(c.GetFileRoute(fileId)+fmt.Sprintf("?download=%v", download), "") + if appErr != nil { + return nil, BuildErrorResponse(r, appErr) } + defer closeBody(r) + + data, err := ioutil.ReadAll(r.Body) + if err != nil { + return nil, BuildErrorResponse(r, NewAppError("DownloadFile", "model.client.read_file.app_error", nil, err.Error(), r.StatusCode)) + } + return data, BuildResponse(r) } // GetFileThumbnail gets the bytes for a file by id. func (c *Client4) GetFileThumbnail(fileId string) ([]byte, *Response) { - if r, err := c.DoApiGet(c.GetFileRoute(fileId)+"/thumbnail", ""); err != nil { - return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - - if data, err := ioutil.ReadAll(r.Body); err != nil { - return nil, BuildErrorResponse(r, NewAppError("GetFileThumbnail", "model.client.read_file.app_error", nil, err.Error(), r.StatusCode)) - } else { - return data, BuildResponse(r) - } + r, appErr := c.DoApiGet(c.GetFileRoute(fileId)+"/thumbnail", "") + if appErr != nil { + return nil, BuildErrorResponse(r, appErr) } + defer closeBody(r) + + data, err := ioutil.ReadAll(r.Body) + if err != nil { + return nil, BuildErrorResponse(r, NewAppError("GetFileThumbnail", "model.client.read_file.app_error", nil, err.Error(), r.StatusCode)) + } + return data, BuildResponse(r) } // DownloadFileThumbnail gets the bytes for a file by id, optionally adding headers to force the browser to download it. func (c *Client4) DownloadFileThumbnail(fileId string, download bool) ([]byte, *Response) { - if r, err := c.DoApiGet(c.GetFileRoute(fileId)+fmt.Sprintf("/thumbnail?download=%v", download), ""); err != nil { - return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - - if data, err := ioutil.ReadAll(r.Body); err != nil { - return nil, BuildErrorResponse(r, NewAppError("DownloadFileThumbnail", "model.client.read_file.app_error", nil, err.Error(), r.StatusCode)) - } else { - return data, BuildResponse(r) - } + r, appErr := c.DoApiGet(c.GetFileRoute(fileId)+fmt.Sprintf("/thumbnail?download=%v", download), "") + if appErr != nil { + return nil, BuildErrorResponse(r, appErr) } + defer closeBody(r) + + data, err := ioutil.ReadAll(r.Body) + if err != nil { + return nil, BuildErrorResponse(r, NewAppError("DownloadFileThumbnail", "model.client.read_file.app_error", nil, err.Error(), r.StatusCode)) + } + return data, BuildResponse(r) } // GetFileLink gets the public link of a file by id. func (c *Client4) GetFileLink(fileId string) (string, *Response) { - if r, err := c.DoApiGet(c.GetFileRoute(fileId)+"/link", ""); err != nil { + r, err := c.DoApiGet(c.GetFileRoute(fileId)+"/link", "") + if err != nil { return "", BuildErrorResponse(r, err) - } else { - defer closeBody(r) - - return MapFromJson(r.Body)["link"], BuildResponse(r) } + defer closeBody(r) + return MapFromJson(r.Body)["link"], BuildResponse(r) } // GetFilePreview gets the bytes for a file by id. func (c *Client4) GetFilePreview(fileId string) ([]byte, *Response) { - if r, err := c.DoApiGet(c.GetFileRoute(fileId)+"/preview", ""); err != nil { - return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - - if data, err := ioutil.ReadAll(r.Body); err != nil { - return nil, BuildErrorResponse(r, NewAppError("GetFilePreview", "model.client.read_file.app_error", nil, err.Error(), r.StatusCode)) - } else { - return data, BuildResponse(r) - } + r, appErr := c.DoApiGet(c.GetFileRoute(fileId)+"/preview", "") + if appErr != nil { + return nil, BuildErrorResponse(r, appErr) } + defer closeBody(r) + + data, err := ioutil.ReadAll(r.Body) + if err != nil { + return nil, BuildErrorResponse(r, NewAppError("GetFilePreview", "model.client.read_file.app_error", nil, err.Error(), r.StatusCode)) + } + return data, BuildResponse(r) } // DownloadFilePreview gets the bytes for a file by id. func (c *Client4) DownloadFilePreview(fileId string, download bool) ([]byte, *Response) { - if r, err := c.DoApiGet(c.GetFileRoute(fileId)+fmt.Sprintf("/preview?download=%v", download), ""); err != nil { - return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - - if data, err := ioutil.ReadAll(r.Body); err != nil { - return nil, BuildErrorResponse(r, NewAppError("DownloadFilePreview", "model.client.read_file.app_error", nil, err.Error(), r.StatusCode)) - } else { - return data, BuildResponse(r) - } + r, appErr := c.DoApiGet(c.GetFileRoute(fileId)+fmt.Sprintf("/preview?download=%v", download), "") + if appErr != nil { + return nil, BuildErrorResponse(r, appErr) } + defer closeBody(r) + + data, err := ioutil.ReadAll(r.Body) + if err != nil { + return nil, BuildErrorResponse(r, NewAppError("DownloadFilePreview", "model.client.read_file.app_error", nil, err.Error(), r.StatusCode)) + } + return data, BuildResponse(r) } // GetFileInfo gets all the file info objects. func (c *Client4) GetFileInfo(fileId string) (*FileInfo, *Response) { - if r, err := c.DoApiGet(c.GetFileRoute(fileId)+"/info", ""); err != nil { + r, err := c.DoApiGet(c.GetFileRoute(fileId)+"/info", "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return FileInfoFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return FileInfoFromJson(r.Body), BuildResponse(r) } // GetFileInfosForPost gets all the file info objects attached to a post. func (c *Client4) GetFileInfosForPost(postId string, etag string) ([]*FileInfo, *Response) { - if r, err := c.DoApiGet(c.GetPostRoute(postId)+"/files/info", etag); err != nil { + r, err := c.DoApiGet(c.GetPostRoute(postId)+"/files/info", etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return FileInfosFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return FileInfosFromJson(r.Body), BuildResponse(r) } // General/System Section // GetPing will return ok if the running goRoutines are below the threshold and unhealthy for above. func (c *Client4) GetPing() (string, *Response) { - if r, err := c.DoApiGet(c.GetSystemRoute()+"/ping", ""); r != nil && r.StatusCode == 500 { + r, err := c.DoApiGet(c.GetSystemRoute()+"/ping", "") + if r != nil && r.StatusCode == 500 { defer r.Body.Close() return "unhealthy", BuildErrorResponse(r, err) - } else if err != nil { - return "", BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return MapFromJson(r.Body)["status"], BuildResponse(r) } + if err != nil { + return "", BuildErrorResponse(r, err) + } + defer closeBody(r) + return MapFromJson(r.Body)["status"], BuildResponse(r) } // TestEmail will attempt to connect to the configured SMTP server. func (c *Client4) TestEmail(config *Config) (bool, *Response) { - if r, err := c.DoApiPost(c.GetTestEmailRoute(), config.ToJson()); err != nil { + r, err := c.DoApiPost(c.GetTestEmailRoute(), config.ToJson()) + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } // TestS3Connection will attempt to connect to the AWS S3. func (c *Client4) TestS3Connection(config *Config) (bool, *Response) { - if r, err := c.DoApiPost(c.GetTestS3Route(), config.ToJson()); err != nil { + r, err := c.DoApiPost(c.GetTestS3Route(), config.ToJson()) + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } // GetConfig will retrieve the server config with some sanitized items. func (c *Client4) GetConfig() (*Config, *Response) { - if r, err := c.DoApiGet(c.GetConfigRoute(), ""); err != nil { + r, err := c.DoApiGet(c.GetConfigRoute(), "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return ConfigFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return ConfigFromJson(r.Body), BuildResponse(r) } // ReloadConfig will reload the server configuration. func (c *Client4) ReloadConfig() (bool, *Response) { - if r, err := c.DoApiPost(c.GetConfigRoute()+"/reload", ""); err != nil { + r, err := c.DoApiPost(c.GetConfigRoute()+"/reload", "") + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } // GetOldClientConfig will retrieve the parts of the server configuration needed by the // client, formatted in the old format. func (c *Client4) GetOldClientConfig(etag string) (map[string]string, *Response) { - if r, err := c.DoApiGet(c.GetConfigRoute()+"/client?format=old", etag); err != nil { + r, err := c.DoApiGet(c.GetConfigRoute()+"/client?format=old", etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return MapFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return MapFromJson(r.Body), BuildResponse(r) } // GetEnvironmentConfig will retrieve a map mirroring the server configuration where fields // are set to true if the corresponding config setting is set through an environment variable. // Settings that haven't been set through environment variables will be missing from the map. func (c *Client4) GetEnvironmentConfig() (map[string]interface{}, *Response) { - if r, err := c.DoApiGet(c.GetConfigRoute()+"/environment", ""); err != nil { + r, err := c.DoApiGet(c.GetConfigRoute()+"/environment", "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return StringInterfaceFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return StringInterfaceFromJson(r.Body), BuildResponse(r) } // GetOldClientLicense will retrieve the parts of the server license needed by the // client, formatted in the old format. func (c *Client4) GetOldClientLicense(etag string) (map[string]string, *Response) { - if r, err := c.DoApiGet(c.GetLicenseRoute()+"/client?format=old", etag); err != nil { + r, err := c.DoApiGet(c.GetLicenseRoute()+"/client?format=old", etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return MapFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return MapFromJson(r.Body), BuildResponse(r) } // DatabaseRecycle will recycle the connections. Discard current connection and get new one. func (c *Client4) DatabaseRecycle() (bool, *Response) { - if r, err := c.DoApiPost(c.GetDatabaseRoute()+"/recycle", ""); err != nil { + r, err := c.DoApiPost(c.GetDatabaseRoute()+"/recycle", "") + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } // InvalidateCaches will purge the cache and can affect the performance while is cleaning. func (c *Client4) InvalidateCaches() (bool, *Response) { - if r, err := c.DoApiPost(c.GetCacheRoute()+"/invalidate", ""); err != nil { + r, err := c.DoApiPost(c.GetCacheRoute()+"/invalidate", "") + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } // UpdateConfig will update the server configuration. func (c *Client4) UpdateConfig(config *Config) (*Config, *Response) { - if r, err := c.DoApiPut(c.GetConfigRoute(), config.ToJson()); err != nil { + r, err := c.DoApiPut(c.GetConfigRoute(), config.ToJson()) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return ConfigFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return ConfigFromJson(r.Body), BuildResponse(r) } // UploadLicenseFile will add a license file to the system. @@ -2552,13 +2574,16 @@ func (c *Client4) UploadLicenseFile(data []byte) (bool, *Response) { body := &bytes.Buffer{} writer := multipart.NewWriter(body) - if part, err := writer.CreateFormFile("license", "test-license.mattermost-license"); err != nil { - return false, &Response{Error: NewAppError("UploadLicenseFile", "model.client.set_profile_user.no_file.app_error", nil, err.Error(), http.StatusBadRequest)} - } else if _, err = io.Copy(part, bytes.NewBuffer(data)); err != nil { + part, err := writer.CreateFormFile("license", "test-license.mattermost-license") + if err != nil { return false, &Response{Error: NewAppError("UploadLicenseFile", "model.client.set_profile_user.no_file.app_error", nil, err.Error(), http.StatusBadRequest)} } - if err := writer.Close(); err != nil { + if _, err = io.Copy(part, bytes.NewBuffer(data)); err != nil { + return false, &Response{Error: NewAppError("UploadLicenseFile", "model.client.set_profile_user.no_file.app_error", nil, err.Error(), http.StatusBadRequest)} + } + + if err = writer.Close(); err != nil { return false, &Response{Error: NewAppError("UploadLicenseFile", "model.client.set_profile_user.writer.app_error", nil, err.Error(), http.StatusBadRequest)} } @@ -2569,28 +2594,28 @@ func (c *Client4) UploadLicenseFile(data []byte) (bool, *Response) { rq.Header.Set(HEADER_AUTH, c.AuthType+" "+c.AuthToken) } - if rp, err := c.HttpClient.Do(rq); err != nil || rp == nil { + rp, err := c.HttpClient.Do(rq) + if err != nil || rp == nil { return false, &Response{StatusCode: http.StatusForbidden, Error: NewAppError(c.GetLicenseRoute(), "model.client.connecting.app_error", nil, err.Error(), http.StatusForbidden)} - } else { - defer closeBody(rp) - - if rp.StatusCode >= 300 { - return false, BuildErrorResponse(rp, AppErrorFromJson(rp.Body)) - } else { - return CheckStatusOK(rp), BuildResponse(rp) - } } + defer closeBody(rp) + + if rp.StatusCode >= 300 { + return false, BuildErrorResponse(rp, AppErrorFromJson(rp.Body)) + } + + return CheckStatusOK(rp), BuildResponse(rp) } // RemoveLicenseFile will remove the server license it exists. Note that this will // disable all enterprise features. func (c *Client4) RemoveLicenseFile() (bool, *Response) { - if r, err := c.DoApiDelete(c.GetLicenseRoute()); err != nil { + r, err := c.DoApiDelete(c.GetLicenseRoute()) + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } // GetAnalyticsOld will retrieve analytics using the old format. New format is not @@ -2599,238 +2624,241 @@ func (c *Client4) RemoveLicenseFile() (bool, *Response) { // to a specific team. func (c *Client4) GetAnalyticsOld(name, teamId string) (AnalyticsRows, *Response) { query := fmt.Sprintf("?name=%v&team_id=%v", name, teamId) - if r, err := c.DoApiGet(c.GetAnalyticsRoute()+"/old"+query, ""); err != nil { + r, err := c.DoApiGet(c.GetAnalyticsRoute()+"/old"+query, "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return AnalyticsRowsFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return AnalyticsRowsFromJson(r.Body), BuildResponse(r) } // Webhooks Section // CreateIncomingWebhook creates an incoming webhook for a channel. func (c *Client4) CreateIncomingWebhook(hook *IncomingWebhook) (*IncomingWebhook, *Response) { - if r, err := c.DoApiPost(c.GetIncomingWebhooksRoute(), hook.ToJson()); err != nil { + r, err := c.DoApiPost(c.GetIncomingWebhooksRoute(), hook.ToJson()) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return IncomingWebhookFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return IncomingWebhookFromJson(r.Body), BuildResponse(r) } // UpdateIncomingWebhook updates an incoming webhook for a channel. func (c *Client4) UpdateIncomingWebhook(hook *IncomingWebhook) (*IncomingWebhook, *Response) { - if r, err := c.DoApiPut(c.GetIncomingWebhookRoute(hook.Id), hook.ToJson()); err != nil { + r, err := c.DoApiPut(c.GetIncomingWebhookRoute(hook.Id), hook.ToJson()) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return IncomingWebhookFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return IncomingWebhookFromJson(r.Body), BuildResponse(r) } // GetIncomingWebhooks returns a page of incoming webhooks on the system. Page counting starts at 0. func (c *Client4) GetIncomingWebhooks(page int, perPage int, etag string) ([]*IncomingWebhook, *Response) { query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage) - if r, err := c.DoApiGet(c.GetIncomingWebhooksRoute()+query, etag); err != nil { + r, err := c.DoApiGet(c.GetIncomingWebhooksRoute()+query, etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return IncomingWebhookListFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return IncomingWebhookListFromJson(r.Body), BuildResponse(r) } // GetIncomingWebhooksForTeam returns a page of incoming webhooks for a team. Page counting starts at 0. func (c *Client4) GetIncomingWebhooksForTeam(teamId string, page int, perPage int, etag string) ([]*IncomingWebhook, *Response) { query := fmt.Sprintf("?page=%v&per_page=%v&team_id=%v", page, perPage, teamId) - if r, err := c.DoApiGet(c.GetIncomingWebhooksRoute()+query, etag); err != nil { + r, err := c.DoApiGet(c.GetIncomingWebhooksRoute()+query, etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return IncomingWebhookListFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return IncomingWebhookListFromJson(r.Body), BuildResponse(r) } -// GetIncomingWebhook returns an Incoming webhook given the hook ID +// GetIncomingWebhook returns an Incoming webhook given the hook ID. func (c *Client4) GetIncomingWebhook(hookID string, etag string) (*IncomingWebhook, *Response) { - if r, err := c.DoApiGet(c.GetIncomingWebhookRoute(hookID), etag); err != nil { + r, err := c.DoApiGet(c.GetIncomingWebhookRoute(hookID), etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return IncomingWebhookFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return IncomingWebhookFromJson(r.Body), BuildResponse(r) } -// DeleteIncomingWebhook deletes and Incoming Webhook given the hook ID +// DeleteIncomingWebhook deletes and Incoming Webhook given the hook ID. func (c *Client4) DeleteIncomingWebhook(hookID string) (bool, *Response) { - if r, err := c.DoApiDelete(c.GetIncomingWebhookRoute(hookID)); err != nil { + r, err := c.DoApiDelete(c.GetIncomingWebhookRoute(hookID)) + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } // CreateOutgoingWebhook creates an outgoing webhook for a team or channel. func (c *Client4) CreateOutgoingWebhook(hook *OutgoingWebhook) (*OutgoingWebhook, *Response) { - if r, err := c.DoApiPost(c.GetOutgoingWebhooksRoute(), hook.ToJson()); err != nil { + r, err := c.DoApiPost(c.GetOutgoingWebhooksRoute(), hook.ToJson()) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return OutgoingWebhookFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return OutgoingWebhookFromJson(r.Body), BuildResponse(r) } // UpdateOutgoingWebhook creates an outgoing webhook for a team or channel. func (c *Client4) UpdateOutgoingWebhook(hook *OutgoingWebhook) (*OutgoingWebhook, *Response) { - if r, err := c.DoApiPut(c.GetOutgoingWebhookRoute(hook.Id), hook.ToJson()); err != nil { + r, err := c.DoApiPut(c.GetOutgoingWebhookRoute(hook.Id), hook.ToJson()) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return OutgoingWebhookFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return OutgoingWebhookFromJson(r.Body), BuildResponse(r) } // GetOutgoingWebhooks returns a page of outgoing webhooks on the system. Page counting starts at 0. func (c *Client4) GetOutgoingWebhooks(page int, perPage int, etag string) ([]*OutgoingWebhook, *Response) { query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage) - if r, err := c.DoApiGet(c.GetOutgoingWebhooksRoute()+query, etag); err != nil { + r, err := c.DoApiGet(c.GetOutgoingWebhooksRoute()+query, etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return OutgoingWebhookListFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return OutgoingWebhookListFromJson(r.Body), BuildResponse(r) } // GetOutgoingWebhook outgoing webhooks on the system requested by Hook Id. func (c *Client4) GetOutgoingWebhook(hookId string) (*OutgoingWebhook, *Response) { - if r, err := c.DoApiGet(c.GetOutgoingWebhookRoute(hookId), ""); err != nil { + r, err := c.DoApiGet(c.GetOutgoingWebhookRoute(hookId), "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return OutgoingWebhookFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return OutgoingWebhookFromJson(r.Body), BuildResponse(r) } // GetOutgoingWebhooksForChannel returns a page of outgoing webhooks for a channel. Page counting starts at 0. func (c *Client4) GetOutgoingWebhooksForChannel(channelId string, page int, perPage int, etag string) ([]*OutgoingWebhook, *Response) { query := fmt.Sprintf("?page=%v&per_page=%v&channel_id=%v", page, perPage, channelId) - if r, err := c.DoApiGet(c.GetOutgoingWebhooksRoute()+query, etag); err != nil { + r, err := c.DoApiGet(c.GetOutgoingWebhooksRoute()+query, etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return OutgoingWebhookListFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return OutgoingWebhookListFromJson(r.Body), BuildResponse(r) } // GetOutgoingWebhooksForTeam returns a page of outgoing webhooks for a team. Page counting starts at 0. func (c *Client4) GetOutgoingWebhooksForTeam(teamId string, page int, perPage int, etag string) ([]*OutgoingWebhook, *Response) { query := fmt.Sprintf("?page=%v&per_page=%v&team_id=%v", page, perPage, teamId) - if r, err := c.DoApiGet(c.GetOutgoingWebhooksRoute()+query, etag); err != nil { + r, err := c.DoApiGet(c.GetOutgoingWebhooksRoute()+query, etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return OutgoingWebhookListFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return OutgoingWebhookListFromJson(r.Body), BuildResponse(r) } // RegenOutgoingHookToken regenerate the outgoing webhook token. func (c *Client4) RegenOutgoingHookToken(hookId string) (*OutgoingWebhook, *Response) { - if r, err := c.DoApiPost(c.GetOutgoingWebhookRoute(hookId)+"/regen_token", ""); err != nil { + r, err := c.DoApiPost(c.GetOutgoingWebhookRoute(hookId)+"/regen_token", "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return OutgoingWebhookFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return OutgoingWebhookFromJson(r.Body), BuildResponse(r) } // DeleteOutgoingWebhook delete the outgoing webhook on the system requested by Hook Id. func (c *Client4) DeleteOutgoingWebhook(hookId string) (bool, *Response) { - if r, err := c.DoApiDelete(c.GetOutgoingWebhookRoute(hookId)); err != nil { + r, err := c.DoApiDelete(c.GetOutgoingWebhookRoute(hookId)) + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } // Preferences Section // GetPreferences returns the user's preferences. func (c *Client4) GetPreferences(userId string) (Preferences, *Response) { - if r, err := c.DoApiGet(c.GetPreferencesRoute(userId), ""); err != nil { + r, err := c.DoApiGet(c.GetPreferencesRoute(userId), "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - preferences, _ := PreferencesFromJson(r.Body) - defer closeBody(r) - return preferences, BuildResponse(r) } + defer closeBody(r) + preferences, _ := PreferencesFromJson(r.Body) + return preferences, BuildResponse(r) } // UpdatePreferences saves the user's preferences. func (c *Client4) UpdatePreferences(userId string, preferences *Preferences) (bool, *Response) { - if r, err := c.DoApiPut(c.GetPreferencesRoute(userId), preferences.ToJson()); err != nil { + r, err := c.DoApiPut(c.GetPreferencesRoute(userId), preferences.ToJson()) + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return true, BuildResponse(r) } + defer closeBody(r) + return true, BuildResponse(r) } // DeletePreferences deletes the user's preferences. func (c *Client4) DeletePreferences(userId string, preferences *Preferences) (bool, *Response) { - if r, err := c.DoApiPost(c.GetPreferencesRoute(userId)+"/delete", preferences.ToJson()); err != nil { + r, err := c.DoApiPost(c.GetPreferencesRoute(userId)+"/delete", preferences.ToJson()) + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return true, BuildResponse(r) } + defer closeBody(r) + return true, BuildResponse(r) } // GetPreferencesByCategory returns the user's preferences from the provided category string. func (c *Client4) GetPreferencesByCategory(userId string, category string) (Preferences, *Response) { url := fmt.Sprintf(c.GetPreferencesRoute(userId)+"/%s", category) - if r, err := c.DoApiGet(url, ""); err != nil { + r, err := c.DoApiGet(url, "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - preferences, _ := PreferencesFromJson(r.Body) - defer closeBody(r) - return preferences, BuildResponse(r) } + defer closeBody(r) + preferences, _ := PreferencesFromJson(r.Body) + return preferences, BuildResponse(r) } // GetPreferenceByCategoryAndName returns the user's preferences from the provided category and preference name string. func (c *Client4) GetPreferenceByCategoryAndName(userId string, category string, preferenceName string) (*Preference, *Response) { url := fmt.Sprintf(c.GetPreferencesRoute(userId)+"/%s/name/%v", category, preferenceName) - if r, err := c.DoApiGet(url, ""); err != nil { + r, err := c.DoApiGet(url, "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return PreferenceFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return PreferenceFromJson(r.Body), BuildResponse(r) } // SAML Section // GetSamlMetadata returns metadata for the SAML configuration. func (c *Client4) GetSamlMetadata() (string, *Response) { - if r, err := c.DoApiGet(c.GetSamlRoute()+"/metadata", ""); err != nil { + r, err := c.DoApiGet(c.GetSamlRoute()+"/metadata", "") + if err != nil { return "", BuildErrorResponse(r, err) - } else { - defer closeBody(r) - buf := new(bytes.Buffer) - buf.ReadFrom(r.Body) - return buf.String(), BuildResponse(r) } + defer closeBody(r) + buf := new(bytes.Buffer) + _, _ = buf.ReadFrom(r.Body) + return buf.String(), BuildResponse(r) } func samlFileToMultipart(data []byte, filename string) ([]byte, *multipart.Writer, error) { body := &bytes.Buffer{} writer := multipart.NewWriter(body) - if part, err := writer.CreateFormFile("certificate", filename); err != nil { + part, err := writer.CreateFormFile("certificate", filename) + if err != nil { return nil, nil, err - } else if _, err = io.Copy(part, bytes.NewBuffer(data)); err != nil { + } + + if _, err = io.Copy(part, bytes.NewBuffer(data)); err != nil { return nil, nil, err } @@ -2876,134 +2904,136 @@ func (c *Client4) UploadSamlPrivateCertificate(data []byte, filename string) (bo // DeleteSamlIdpCertificate deletes the SAML IDP certificate from the server and updates the config to not use it and disable SAML. func (c *Client4) DeleteSamlIdpCertificate() (bool, *Response) { - if r, err := c.DoApiDelete(c.GetSamlRoute() + "/certificate/idp"); err != nil { + r, err := c.DoApiDelete(c.GetSamlRoute() + "/certificate/idp") + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } // DeleteSamlPublicCertificate deletes the SAML IDP certificate from the server and updates the config to not use it and disable SAML. func (c *Client4) DeleteSamlPublicCertificate() (bool, *Response) { - if r, err := c.DoApiDelete(c.GetSamlRoute() + "/certificate/public"); err != nil { + r, err := c.DoApiDelete(c.GetSamlRoute() + "/certificate/public") + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } // DeleteSamlPrivateCertificate deletes the SAML IDP certificate from the server and updates the config to not use it and disable SAML. func (c *Client4) DeleteSamlPrivateCertificate() (bool, *Response) { - if r, err := c.DoApiDelete(c.GetSamlRoute() + "/certificate/private"); err != nil { + r, err := c.DoApiDelete(c.GetSamlRoute() + "/certificate/private") + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } // GetSamlCertificateStatus returns metadata for the SAML configuration. func (c *Client4) GetSamlCertificateStatus() (*SamlCertificateStatus, *Response) { - if r, err := c.DoApiGet(c.GetSamlRoute()+"/certificate/status", ""); err != nil { + r, err := c.DoApiGet(c.GetSamlRoute()+"/certificate/status", "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return SamlCertificateStatusFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return SamlCertificateStatusFromJson(r.Body), BuildResponse(r) } // Compliance Section // CreateComplianceReport creates an incoming webhook for a channel. func (c *Client4) CreateComplianceReport(report *Compliance) (*Compliance, *Response) { - if r, err := c.DoApiPost(c.GetComplianceReportsRoute(), report.ToJson()); err != nil { + r, err := c.DoApiPost(c.GetComplianceReportsRoute(), report.ToJson()) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return ComplianceFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return ComplianceFromJson(r.Body), BuildResponse(r) } // GetComplianceReports returns list of compliance reports. func (c *Client4) GetComplianceReports(page, perPage int) (Compliances, *Response) { query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage) - if r, err := c.DoApiGet(c.GetComplianceReportsRoute()+query, ""); err != nil { + r, err := c.DoApiGet(c.GetComplianceReportsRoute()+query, "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CompliancesFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return CompliancesFromJson(r.Body), BuildResponse(r) } // GetComplianceReport returns a compliance report. func (c *Client4) GetComplianceReport(reportId string) (*Compliance, *Response) { - if r, err := c.DoApiGet(c.GetComplianceReportRoute(reportId), ""); err != nil { + r, err := c.DoApiGet(c.GetComplianceReportRoute(reportId), "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return ComplianceFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return ComplianceFromJson(r.Body), BuildResponse(r) } // DownloadComplianceReport returns a full compliance report as a file. func (c *Client4) DownloadComplianceReport(reportId string) ([]byte, *Response) { - var rq *http.Request - rq, _ = http.NewRequest("GET", c.ApiUrl+c.GetComplianceReportRoute(reportId), nil) + rq, _ := http.NewRequest("GET", c.ApiUrl+c.GetComplianceReportRoute(reportId), nil) if len(c.AuthToken) > 0 { rq.Header.Set(HEADER_AUTH, "BEARER "+c.AuthToken) } - if rp, err := c.HttpClient.Do(rq); err != nil || rp == nil { + rp, err := c.HttpClient.Do(rq) + if err != nil || rp == nil { return nil, &Response{Error: NewAppError("DownloadComplianceReport", "model.client.connecting.app_error", nil, err.Error(), http.StatusBadRequest)} - } else { - defer closeBody(rp) - - if rp.StatusCode >= 300 { - return nil, BuildErrorResponse(rp, AppErrorFromJson(rp.Body)) - } else if data, err := ioutil.ReadAll(rp.Body); err != nil { - return nil, BuildErrorResponse(rp, NewAppError("DownloadComplianceReport", "model.client.read_file.app_error", nil, err.Error(), rp.StatusCode)) - } else { - return data, BuildResponse(rp) - } } + defer closeBody(rp) + + if rp.StatusCode >= 300 { + return nil, BuildErrorResponse(rp, AppErrorFromJson(rp.Body)) + } + + data, err := ioutil.ReadAll(rp.Body) + if err != nil { + return nil, BuildErrorResponse(rp, NewAppError("DownloadComplianceReport", "model.client.read_file.app_error", nil, err.Error(), rp.StatusCode)) + } + + return data, BuildResponse(rp) } // Cluster Section // GetClusterStatus returns the status of all the configured cluster nodes. func (c *Client4) GetClusterStatus() ([]*ClusterInfo, *Response) { - if r, err := c.DoApiGet(c.GetClusterRoute()+"/status", ""); err != nil { + r, err := c.DoApiGet(c.GetClusterRoute()+"/status", "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return ClusterInfosFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return ClusterInfosFromJson(r.Body), BuildResponse(r) } // LDAP Section // SyncLdap will force a sync with the configured LDAP server. func (c *Client4) SyncLdap() (bool, *Response) { - if r, err := c.DoApiPost(c.GetLdapRoute()+"/sync", ""); err != nil { + r, err := c.DoApiPost(c.GetLdapRoute()+"/sync", "") + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } // TestLdap will attempt to connect to the configured LDAP server and return OK if configured // correctly. func (c *Client4) TestLdap() (bool, *Response) { - if r, err := c.DoApiPost(c.GetLdapRoute()+"/test", ""); err != nil { + r, err := c.DoApiPost(c.GetLdapRoute()+"/test", "") + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } // Audits Section @@ -3011,40 +3041,42 @@ func (c *Client4) TestLdap() (bool, *Response) { // GetAudits returns a list of audits for the whole system. func (c *Client4) GetAudits(page int, perPage int, etag string) (Audits, *Response) { query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage) - if r, err := c.DoApiGet("/audits"+query, etag); err != nil { + r, err := c.DoApiGet("/audits"+query, etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return AuditsFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return AuditsFromJson(r.Body), BuildResponse(r) } // Brand Section // GetBrandImage retrieves the previously uploaded brand image. func (c *Client4) GetBrandImage() ([]byte, *Response) { - if r, err := c.DoApiGet(c.GetBrandRoute()+"/image", ""); err != nil { - return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - - if r.StatusCode >= 300 { - return nil, BuildErrorResponse(r, AppErrorFromJson(r.Body)) - } else if data, err := ioutil.ReadAll(r.Body); err != nil { - return nil, BuildErrorResponse(r, NewAppError("GetBrandImage", "model.client.read_file.app_error", nil, err.Error(), r.StatusCode)) - } else { - return data, BuildResponse(r) - } + r, appErr := c.DoApiGet(c.GetBrandRoute()+"/image", "") + if appErr != nil { + return nil, BuildErrorResponse(r, appErr) } + defer closeBody(r) + + if r.StatusCode >= 300 { + return nil, BuildErrorResponse(r, AppErrorFromJson(r.Body)) + } + + data, err := ioutil.ReadAll(r.Body) + if err != nil { + return nil, BuildErrorResponse(r, NewAppError("GetBrandImage", "model.client.read_file.app_error", nil, err.Error(), r.StatusCode)) + } + + return data, BuildResponse(r) } +// DeleteBrandImage delets the brand image for the system. func (c *Client4) DeleteBrandImage() *Response { r, err := c.DoApiDelete(c.GetBrandRoute() + "/image") - if err != nil { return BuildErrorResponse(r, err) } - return BuildResponse(r) } @@ -3053,13 +3085,16 @@ func (c *Client4) UploadBrandImage(data []byte) (bool, *Response) { body := &bytes.Buffer{} writer := multipart.NewWriter(body) - if part, err := writer.CreateFormFile("image", "brand.png"); err != nil { - return false, &Response{Error: NewAppError("UploadBrandImage", "model.client.set_profile_user.no_file.app_error", nil, err.Error(), http.StatusBadRequest)} - } else if _, err = io.Copy(part, bytes.NewBuffer(data)); err != nil { + part, err := writer.CreateFormFile("image", "brand.png") + if err != nil { return false, &Response{Error: NewAppError("UploadBrandImage", "model.client.set_profile_user.no_file.app_error", nil, err.Error(), http.StatusBadRequest)} } - if err := writer.Close(); err != nil { + if _, err = io.Copy(part, bytes.NewBuffer(data)); err != nil { + return false, &Response{Error: NewAppError("UploadBrandImage", "model.client.set_profile_user.no_file.app_error", nil, err.Error(), http.StatusBadRequest)} + } + + if err = writer.Close(); err != nil { return false, &Response{Error: NewAppError("UploadBrandImage", "model.client.set_profile_user.writer.app_error", nil, err.Error(), http.StatusBadRequest)} } @@ -3070,17 +3105,17 @@ func (c *Client4) UploadBrandImage(data []byte) (bool, *Response) { rq.Header.Set(HEADER_AUTH, c.AuthType+" "+c.AuthToken) } - if rp, err := c.HttpClient.Do(rq); err != nil || rp == nil { + rp, err := c.HttpClient.Do(rq) + if err != nil || rp == nil { return false, &Response{StatusCode: http.StatusForbidden, Error: NewAppError(c.GetBrandRoute()+"/image", "model.client.connecting.app_error", nil, err.Error(), http.StatusForbidden)} - } else { - defer closeBody(rp) - - if rp.StatusCode >= 300 { - return false, BuildErrorResponse(rp, AppErrorFromJson(rp.Body)) - } else { - return CheckStatusOK(rp), BuildResponse(rp) - } } + defer closeBody(rp) + + if rp.StatusCode >= 300 { + return false, BuildErrorResponse(rp, AppErrorFromJson(rp.Body)) + } + + return CheckStatusOK(rp), BuildResponse(rp) } // Logs Section @@ -3088,129 +3123,129 @@ func (c *Client4) UploadBrandImage(data []byte) (bool, *Response) { // GetLogs page of logs as a string array. func (c *Client4) GetLogs(page, perPage int) ([]string, *Response) { query := fmt.Sprintf("?page=%v&logs_per_page=%v", page, perPage) - if r, err := c.DoApiGet("/logs"+query, ""); err != nil { + r, err := c.DoApiGet("/logs"+query, "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return ArrayFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return ArrayFromJson(r.Body), BuildResponse(r) } // PostLog is a convenience Web Service call so clients can log messages into -// the server-side logs. For example we typically log javascript error messages -// into the server-side. It returns the log message if the logging was successful. +// the server-side logs. For example we typically log javascript error messages +// into the server-side. It returns the log message if the logging was successful. func (c *Client4) PostLog(message map[string]string) (map[string]string, *Response) { - if r, err := c.DoApiPost("/logs", MapToJson(message)); err != nil { + r, err := c.DoApiPost("/logs", MapToJson(message)) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return MapFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return MapFromJson(r.Body), BuildResponse(r) } // OAuth Section // CreateOAuthApp will register a new OAuth 2.0 client application with Mattermost acting as an OAuth 2.0 service provider. func (c *Client4) CreateOAuthApp(app *OAuthApp) (*OAuthApp, *Response) { - if r, err := c.DoApiPost(c.GetOAuthAppsRoute(), app.ToJson()); err != nil { + r, err := c.DoApiPost(c.GetOAuthAppsRoute(), app.ToJson()) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return OAuthAppFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return OAuthAppFromJson(r.Body), BuildResponse(r) } -// UpdateOAuthApp +// UpdateOAuthApp updates a page of registered OAuth 2.0 client applications with Mattermost acting as an OAuth 2.0 service provider. func (c *Client4) UpdateOAuthApp(app *OAuthApp) (*OAuthApp, *Response) { - if r, err := c.DoApiPut(c.GetOAuthAppRoute(app.Id), app.ToJson()); err != nil { + r, err := c.DoApiPut(c.GetOAuthAppRoute(app.Id), app.ToJson()) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return OAuthAppFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return OAuthAppFromJson(r.Body), BuildResponse(r) } // GetOAuthApps gets a page of registered OAuth 2.0 client applications with Mattermost acting as an OAuth 2.0 service provider. func (c *Client4) GetOAuthApps(page, perPage int) ([]*OAuthApp, *Response) { query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage) - if r, err := c.DoApiGet(c.GetOAuthAppsRoute()+query, ""); err != nil { + r, err := c.DoApiGet(c.GetOAuthAppsRoute()+query, "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return OAuthAppListFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return OAuthAppListFromJson(r.Body), BuildResponse(r) } // GetOAuthApp gets a registered OAuth 2.0 client application with Mattermost acting as an OAuth 2.0 service provider. func (c *Client4) GetOAuthApp(appId string) (*OAuthApp, *Response) { - if r, err := c.DoApiGet(c.GetOAuthAppRoute(appId), ""); err != nil { + r, err := c.DoApiGet(c.GetOAuthAppRoute(appId), "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return OAuthAppFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return OAuthAppFromJson(r.Body), BuildResponse(r) } // GetOAuthAppInfo gets a sanitized version of a registered OAuth 2.0 client application with Mattermost acting as an OAuth 2.0 service provider. func (c *Client4) GetOAuthAppInfo(appId string) (*OAuthApp, *Response) { - if r, err := c.DoApiGet(c.GetOAuthAppRoute(appId)+"/info", ""); err != nil { + r, err := c.DoApiGet(c.GetOAuthAppRoute(appId)+"/info", "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return OAuthAppFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return OAuthAppFromJson(r.Body), BuildResponse(r) } // DeleteOAuthApp deletes a registered OAuth 2.0 client application. func (c *Client4) DeleteOAuthApp(appId string) (bool, *Response) { - if r, err := c.DoApiDelete(c.GetOAuthAppRoute(appId)); err != nil { + r, err := c.DoApiDelete(c.GetOAuthAppRoute(appId)) + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } // RegenerateOAuthAppSecret regenerates the client secret for a registered OAuth 2.0 client application. func (c *Client4) RegenerateOAuthAppSecret(appId string) (*OAuthApp, *Response) { - if r, err := c.DoApiPost(c.GetOAuthAppRoute(appId)+"/regen_secret", ""); err != nil { + r, err := c.DoApiPost(c.GetOAuthAppRoute(appId)+"/regen_secret", "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return OAuthAppFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return OAuthAppFromJson(r.Body), BuildResponse(r) } // GetAuthorizedOAuthAppsForUser gets a page of OAuth 2.0 client applications the user has authorized to use access their account. func (c *Client4) GetAuthorizedOAuthAppsForUser(userId string, page, perPage int) ([]*OAuthApp, *Response) { query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage) - if r, err := c.DoApiGet(c.GetUserRoute(userId)+"/oauth/apps/authorized"+query, ""); err != nil { + r, err := c.DoApiGet(c.GetUserRoute(userId)+"/oauth/apps/authorized"+query, "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return OAuthAppListFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return OAuthAppListFromJson(r.Body), BuildResponse(r) } // AuthorizeOAuthApp will authorize an OAuth 2.0 client application to access a user's account and provide a redirect link to follow. func (c *Client4) AuthorizeOAuthApp(authRequest *AuthorizeRequest) (string, *Response) { - if r, err := c.DoApiRequest(http.MethodPost, c.Url+"/oauth/authorize", authRequest.ToJson(), ""); err != nil { + r, err := c.DoApiRequest(http.MethodPost, c.Url+"/oauth/authorize", authRequest.ToJson(), "") + if err != nil { return "", BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return MapFromJson(r.Body)["redirect"], BuildResponse(r) } + defer closeBody(r) + return MapFromJson(r.Body)["redirect"], BuildResponse(r) } // DeauthorizeOAuthApp will deauthorize an OAuth 2.0 client application from accessing a user's account. func (c *Client4) DeauthorizeOAuthApp(appId string) (bool, *Response) { requestData := map[string]string{"client_id": appId} - if r, err := c.DoApiRequest(http.MethodPost, c.Url+"/oauth/deauthorize", MapToJson(requestData), ""); err != nil { + r, err := c.DoApiRequest(http.MethodPost, c.Url+"/oauth/deauthorize", MapToJson(requestData), "") + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } // GetOAuthAccessToken is a test helper function for the OAuth access token endpoint. @@ -3222,94 +3257,95 @@ func (c *Client4) GetOAuthAccessToken(data url.Values) (*AccessResponse, *Respon rq.Header.Set(HEADER_AUTH, c.AuthType+" "+c.AuthToken) } - if rp, err := c.HttpClient.Do(rq); err != nil || rp == nil { + rp, err := c.HttpClient.Do(rq) + if err != nil || rp == nil { return nil, &Response{StatusCode: http.StatusForbidden, Error: NewAppError(c.Url+"/oauth/access_token", "model.client.connecting.app_error", nil, err.Error(), 403)} - } else { - defer closeBody(rp) - if rp.StatusCode >= 300 { - return nil, BuildErrorResponse(rp, AppErrorFromJson(rp.Body)) - } else { - return AccessResponseFromJson(rp.Body), BuildResponse(rp) - } } + defer closeBody(rp) + + if rp.StatusCode >= 300 { + return nil, BuildErrorResponse(rp, AppErrorFromJson(rp.Body)) + } + + return AccessResponseFromJson(rp.Body), BuildResponse(rp) } // Elasticsearch Section -// TestElasticsearch will attempt to connect to the configured Elasticsearch server and return OK if configured +// TestElasticsearch will attempt to connect to the configured Elasticsearch server and return OK if configured. // correctly. func (c *Client4) TestElasticsearch() (bool, *Response) { - if r, err := c.DoApiPost(c.GetElasticsearchRoute()+"/test", ""); err != nil { + r, err := c.DoApiPost(c.GetElasticsearchRoute()+"/test", "") + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } // PurgeElasticsearchIndexes immediately deletes all Elasticsearch indexes. func (c *Client4) PurgeElasticsearchIndexes() (bool, *Response) { - if r, err := c.DoApiPost(c.GetElasticsearchRoute()+"/purge_indexes", ""); err != nil { + r, err := c.DoApiPost(c.GetElasticsearchRoute()+"/purge_indexes", "") + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } // Data Retention Section // GetDataRetentionPolicy will get the current server data retention policy details. func (c *Client4) GetDataRetentionPolicy() (*DataRetentionPolicy, *Response) { - if r, err := c.DoApiGet(c.GetDataRetentionRoute()+"/policy", ""); err != nil { + r, err := c.DoApiGet(c.GetDataRetentionRoute()+"/policy", "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return DataRetentionPolicyFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return DataRetentionPolicyFromJson(r.Body), BuildResponse(r) } // Commands Section // CreateCommand will create a new command if the user have the right permissions. func (c *Client4) CreateCommand(cmd *Command) (*Command, *Response) { - if r, err := c.DoApiPost(c.GetCommandsRoute(), cmd.ToJson()); err != nil { + r, err := c.DoApiPost(c.GetCommandsRoute(), cmd.ToJson()) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CommandFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return CommandFromJson(r.Body), BuildResponse(r) } -// UpdateCommand updates a command based on the provided Command struct +// UpdateCommand updates a command based on the provided Command struct. func (c *Client4) UpdateCommand(cmd *Command) (*Command, *Response) { - if r, err := c.DoApiPut(c.GetCommandRoute(cmd.Id), cmd.ToJson()); err != nil { + r, err := c.DoApiPut(c.GetCommandRoute(cmd.Id), cmd.ToJson()) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CommandFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return CommandFromJson(r.Body), BuildResponse(r) } -// DeleteCommand deletes a command based on the provided command id string +// DeleteCommand deletes a command based on the provided command id string. func (c *Client4) DeleteCommand(commandId string) (bool, *Response) { - if r, err := c.DoApiDelete(c.GetCommandRoute(commandId)); err != nil { + r, err := c.DoApiDelete(c.GetCommandRoute(commandId)) + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } // ListCommands will retrieve a list of commands available in the team. func (c *Client4) ListCommands(teamId string, customOnly bool) ([]*Command, *Response) { query := fmt.Sprintf("?team_id=%v&custom_only=%v", teamId, customOnly) - if r, err := c.DoApiGet(c.GetCommandsRoute()+query, ""); err != nil { + r, err := c.DoApiGet(c.GetCommandsRoute()+query, "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CommandListFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return CommandListFromJson(r.Body), BuildResponse(r) } // ExecuteCommand executes a given slash command. @@ -3318,85 +3354,84 @@ func (c *Client4) ExecuteCommand(channelId, command string) (*CommandResponse, * ChannelId: channelId, Command: command, } - if r, err := c.DoApiPost(c.GetCommandsRoute()+"/execute", commandArgs.ToJson()); err != nil { + r, err := c.DoApiPost(c.GetCommandsRoute()+"/execute", commandArgs.ToJson()) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - - response, _ := CommandResponseFromJson(r.Body) - return response, BuildResponse(r) } + defer closeBody(r) + + response, _ := CommandResponseFromJson(r.Body) + return response, BuildResponse(r) } -// ExecuteCommand executes a given slash command against the specified team -// Use this when executing slash commands in a DM/GM, since the team id cannot be inferred in that case +// ExecuteCommandWithTeam executes a given slash command against the specified team. +// Use this when executing slash commands in a DM/GM, since the team id cannot be inferred in that case. func (c *Client4) ExecuteCommandWithTeam(channelId, teamId, command string) (*CommandResponse, *Response) { commandArgs := &CommandArgs{ ChannelId: channelId, TeamId: teamId, Command: command, } - if r, err := c.DoApiPost(c.GetCommandsRoute()+"/execute", commandArgs.ToJson()); err != nil { + r, err := c.DoApiPost(c.GetCommandsRoute()+"/execute", commandArgs.ToJson()) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - - response, _ := CommandResponseFromJson(r.Body) - return response, BuildResponse(r) } + defer closeBody(r) + + response, _ := CommandResponseFromJson(r.Body) + return response, BuildResponse(r) } -// ListCommands will retrieve a list of commands available in the team. +// ListAutocompleteCommands will retrieve a list of commands available in the team. func (c *Client4) ListAutocompleteCommands(teamId string) ([]*Command, *Response) { - if r, err := c.DoApiGet(c.GetTeamAutoCompleteCommandsRoute(teamId), ""); err != nil { + r, err := c.DoApiGet(c.GetTeamAutoCompleteCommandsRoute(teamId), "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CommandListFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return CommandListFromJson(r.Body), BuildResponse(r) } // RegenCommandToken will create a new token if the user have the right permissions. func (c *Client4) RegenCommandToken(commandId string) (string, *Response) { - if r, err := c.DoApiPut(c.GetCommandRoute(commandId)+"/regen_token", ""); err != nil { + r, err := c.DoApiPut(c.GetCommandRoute(commandId)+"/regen_token", "") + if err != nil { return "", BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return MapFromJson(r.Body)["token"], BuildResponse(r) } + defer closeBody(r) + return MapFromJson(r.Body)["token"], BuildResponse(r) } // Status Section // GetUserStatus returns a user based on the provided user id string. func (c *Client4) GetUserStatus(userId, etag string) (*Status, *Response) { - if r, err := c.DoApiGet(c.GetUserStatusRoute(userId), etag); err != nil { + r, err := c.DoApiGet(c.GetUserStatusRoute(userId), etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return StatusFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return StatusFromJson(r.Body), BuildResponse(r) } // GetUsersStatusesByIds returns a list of users status based on the provided user ids. func (c *Client4) GetUsersStatusesByIds(userIds []string) ([]*Status, *Response) { - if r, err := c.DoApiPost(c.GetUserStatusesRoute()+"/ids", ArrayToJson(userIds)); err != nil { + r, err := c.DoApiPost(c.GetUserStatusesRoute()+"/ids", ArrayToJson(userIds)) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return StatusListFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return StatusListFromJson(r.Body), BuildResponse(r) } // UpdateUserStatus sets a user's status based on the provided user id string. func (c *Client4) UpdateUserStatus(userId string, userStatus *Status) (*Status, *Response) { - if r, err := c.DoApiPut(c.GetUserStatusRoute(userId), userStatus.ToJson()); err != nil { + r, err := c.DoApiPut(c.GetUserStatusRoute(userId), userStatus.ToJson()) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return StatusFromJson(r.Body), BuildResponse(r) - } + defer closeBody(r) + return StatusFromJson(r.Body), BuildResponse(r) } // Emoji Section @@ -3408,9 +3443,12 @@ func (c *Client4) CreateEmoji(emoji *Emoji, image []byte, filename string) (*Emo body := &bytes.Buffer{} writer := multipart.NewWriter(body) - if part, err := writer.CreateFormFile("image", filename); err != nil { + part, err := writer.CreateFormFile("image", filename) + if err != nil { return nil, &Response{StatusCode: http.StatusForbidden, Error: NewAppError("CreateEmoji", "model.client.create_emoji.image.app_error", nil, err.Error(), 0)} - } else if _, err = io.Copy(part, bytes.NewBuffer(image)); err != nil { + } + + if _, err := io.Copy(part, bytes.NewBuffer(image)); err != nil { return nil, &Response{StatusCode: http.StatusForbidden, Error: NewAppError("CreateEmoji", "model.client.create_emoji.image.app_error", nil, err.Error(), 0)} } @@ -3428,315 +3466,316 @@ func (c *Client4) CreateEmoji(emoji *Emoji, image []byte, filename string) (*Emo // GetEmojiList returns a page of custom emoji on the system. func (c *Client4) GetEmojiList(page, perPage int) ([]*Emoji, *Response) { query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage) - if r, err := c.DoApiGet(c.GetEmojisRoute()+query, ""); err != nil { + r, err := c.DoApiGet(c.GetEmojisRoute()+query, "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return EmojiListFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return EmojiListFromJson(r.Body), BuildResponse(r) } // GetSortedEmojiList returns a page of custom emoji on the system sorted based on the sort // parameter, blank for no sorting and "name" to sort by emoji names. func (c *Client4) GetSortedEmojiList(page, perPage int, sort string) ([]*Emoji, *Response) { query := fmt.Sprintf("?page=%v&per_page=%v&sort=%v", page, perPage, sort) - if r, err := c.DoApiGet(c.GetEmojisRoute()+query, ""); err != nil { + r, err := c.DoApiGet(c.GetEmojisRoute()+query, "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return EmojiListFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return EmojiListFromJson(r.Body), BuildResponse(r) } // DeleteEmoji delete an custom emoji on the provided emoji id string. func (c *Client4) DeleteEmoji(emojiId string) (bool, *Response) { - if r, err := c.DoApiDelete(c.GetEmojiRoute(emojiId)); err != nil { + r, err := c.DoApiDelete(c.GetEmojiRoute(emojiId)) + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } // GetEmoji returns a custom emoji based on the emojiId string. func (c *Client4) GetEmoji(emojiId string) (*Emoji, *Response) { - if r, err := c.DoApiGet(c.GetEmojiRoute(emojiId), ""); err != nil { + r, err := c.DoApiGet(c.GetEmojiRoute(emojiId), "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return EmojiFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return EmojiFromJson(r.Body), BuildResponse(r) } // GetEmojiByName returns a custom emoji based on the name string. func (c *Client4) GetEmojiByName(name string) (*Emoji, *Response) { - if r, err := c.DoApiGet(c.GetEmojiByNameRoute(name), ""); err != nil { + r, err := c.DoApiGet(c.GetEmojiByNameRoute(name), "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return EmojiFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return EmojiFromJson(r.Body), BuildResponse(r) } // GetEmojiImage returns the emoji image. func (c *Client4) GetEmojiImage(emojiId string) ([]byte, *Response) { - if r, err := c.DoApiGet(c.GetEmojiRoute(emojiId)+"/image", ""); err != nil { - return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - - if data, err := ioutil.ReadAll(r.Body); err != nil { - return nil, BuildErrorResponse(r, NewAppError("GetEmojiImage", "model.client.read_file.app_error", nil, err.Error(), r.StatusCode)) - } else { - return data, BuildResponse(r) - } + r, apErr := c.DoApiGet(c.GetEmojiRoute(emojiId)+"/image", "") + if apErr != nil { + return nil, BuildErrorResponse(r, apErr) } + defer closeBody(r) + + data, err := ioutil.ReadAll(r.Body) + if err != nil { + return nil, BuildErrorResponse(r, NewAppError("GetEmojiImage", "model.client.read_file.app_error", nil, err.Error(), r.StatusCode)) + } + + return data, BuildResponse(r) } // SearchEmoji returns a list of emoji matching some search criteria. func (c *Client4) SearchEmoji(search *EmojiSearch) ([]*Emoji, *Response) { - if r, err := c.DoApiPost(c.GetEmojisRoute()+"/search", search.ToJson()); err != nil { + r, err := c.DoApiPost(c.GetEmojisRoute()+"/search", search.ToJson()) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return EmojiListFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return EmojiListFromJson(r.Body), BuildResponse(r) } // AutocompleteEmoji returns a list of emoji starting with or matching name. func (c *Client4) AutocompleteEmoji(name string, etag string) ([]*Emoji, *Response) { query := fmt.Sprintf("?name=%v", name) - if r, err := c.DoApiGet(c.GetEmojisRoute()+"/autocomplete"+query, ""); err != nil { + r, err := c.DoApiGet(c.GetEmojisRoute()+"/autocomplete"+query, "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return EmojiListFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return EmojiListFromJson(r.Body), BuildResponse(r) } // Reaction Section // SaveReaction saves an emoji reaction for a post. Returns the saved reaction if successful, otherwise an error will be returned. func (c *Client4) SaveReaction(reaction *Reaction) (*Reaction, *Response) { - if r, err := c.DoApiPost(c.GetReactionsRoute(), reaction.ToJson()); err != nil { + r, err := c.DoApiPost(c.GetReactionsRoute(), reaction.ToJson()) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return ReactionFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return ReactionFromJson(r.Body), BuildResponse(r) } // GetReactions returns a list of reactions to a post. func (c *Client4) GetReactions(postId string) ([]*Reaction, *Response) { - if r, err := c.DoApiGet(c.GetPostRoute(postId)+"/reactions", ""); err != nil { + r, err := c.DoApiGet(c.GetPostRoute(postId)+"/reactions", "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return ReactionsFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return ReactionsFromJson(r.Body), BuildResponse(r) } // DeleteReaction deletes reaction of a user in a post. func (c *Client4) DeleteReaction(reaction *Reaction) (bool, *Response) { - if r, err := c.DoApiDelete(c.GetUserRoute(reaction.UserId) + c.GetPostRoute(reaction.PostId) + fmt.Sprintf("/reactions/%v", reaction.EmojiName)); err != nil { + r, err := c.DoApiDelete(c.GetUserRoute(reaction.UserId) + c.GetPostRoute(reaction.PostId) + fmt.Sprintf("/reactions/%v", reaction.EmojiName)) + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } // Timezone Section // GetSupportedTimezone returns a page of supported timezones on the system. func (c *Client4) GetSupportedTimezone() (SupportedTimezones, *Response) { - if r, err := c.DoApiGet(c.GetTimezonesRoute(), ""); err != nil { + r, err := c.DoApiGet(c.GetTimezonesRoute(), "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return TimezonesFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return TimezonesFromJson(r.Body), BuildResponse(r) } // Open Graph Metadata Section -// OpenGraph return the open graph metadata for a particular url if the site have the metadata +// OpenGraph return the open graph metadata for a particular url if the site have the metadata. func (c *Client4) OpenGraph(url string) (map[string]string, *Response) { requestBody := make(map[string]string) requestBody["url"] = url - if r, err := c.DoApiPost(c.GetOpenGraphRoute(), MapToJson(requestBody)); err != nil { + r, err := c.DoApiPost(c.GetOpenGraphRoute(), MapToJson(requestBody)) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return MapFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return MapFromJson(r.Body), BuildResponse(r) } // Jobs Section // GetJob gets a single job. func (c *Client4) GetJob(id string) (*Job, *Response) { - if r, err := c.DoApiGet(c.GetJobsRoute()+fmt.Sprintf("/%v", id), ""); err != nil { + r, err := c.DoApiGet(c.GetJobsRoute()+fmt.Sprintf("/%v", id), "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return JobFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return JobFromJson(r.Body), BuildResponse(r) } -// Get all jobs, sorted with the job that was created most recently first. +// GetJobs gets all jobs, sorted with the job that was created most recently first. func (c *Client4) GetJobs(page int, perPage int) ([]*Job, *Response) { - if r, err := c.DoApiGet(c.GetJobsRoute()+fmt.Sprintf("?page=%v&per_page=%v", page, perPage), ""); err != nil { + r, err := c.DoApiGet(c.GetJobsRoute()+fmt.Sprintf("?page=%v&per_page=%v", page, perPage), "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return JobsFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return JobsFromJson(r.Body), BuildResponse(r) } // GetJobsByType gets all jobs of a given type, sorted with the job that was created most recently first. func (c *Client4) GetJobsByType(jobType string, page int, perPage int) ([]*Job, *Response) { - if r, err := c.DoApiGet(c.GetJobsRoute()+fmt.Sprintf("/type/%v?page=%v&per_page=%v", jobType, page, perPage), ""); err != nil { + r, err := c.DoApiGet(c.GetJobsRoute()+fmt.Sprintf("/type/%v?page=%v&per_page=%v", jobType, page, perPage), "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return JobsFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return JobsFromJson(r.Body), BuildResponse(r) } // CreateJob creates a job based on the provided job struct. func (c *Client4) CreateJob(job *Job) (*Job, *Response) { - if r, err := c.DoApiPost(c.GetJobsRoute(), job.ToJson()); err != nil { + r, err := c.DoApiPost(c.GetJobsRoute(), job.ToJson()) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return JobFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return JobFromJson(r.Body), BuildResponse(r) } // CancelJob requests the cancellation of the job with the provided Id. func (c *Client4) CancelJob(jobId string) (bool, *Response) { - if r, err := c.DoApiPost(c.GetJobsRoute()+fmt.Sprintf("/%v/cancel", jobId), ""); err != nil { + r, err := c.DoApiPost(c.GetJobsRoute()+fmt.Sprintf("/%v/cancel", jobId), "") + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } // Roles Section // GetRole gets a single role by ID. func (c *Client4) GetRole(id string) (*Role, *Response) { - if r, err := c.DoApiGet(c.GetRolesRoute()+fmt.Sprintf("/%v", id), ""); err != nil { + r, err := c.DoApiGet(c.GetRolesRoute()+fmt.Sprintf("/%v", id), "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return RoleFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return RoleFromJson(r.Body), BuildResponse(r) } // GetRoleByName gets a single role by Name. func (c *Client4) GetRoleByName(name string) (*Role, *Response) { - if r, err := c.DoApiGet(c.GetRolesRoute()+fmt.Sprintf("/name/%v", name), ""); err != nil { + r, err := c.DoApiGet(c.GetRolesRoute()+fmt.Sprintf("/name/%v", name), "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return RoleFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return RoleFromJson(r.Body), BuildResponse(r) } // GetRolesByNames returns a list of roles based on the provided role names. func (c *Client4) GetRolesByNames(roleNames []string) ([]*Role, *Response) { - if r, err := c.DoApiPost(c.GetRolesRoute()+"/names", ArrayToJson(roleNames)); err != nil { + r, err := c.DoApiPost(c.GetRolesRoute()+"/names", ArrayToJson(roleNames)) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return RoleListFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return RoleListFromJson(r.Body), BuildResponse(r) } // PatchRole partially updates a role in the system. Any missing fields are not updated. func (c *Client4) PatchRole(roleId string, patch *RolePatch) (*Role, *Response) { - if r, err := c.DoApiPut(c.GetRolesRoute()+fmt.Sprintf("/%v/patch", roleId), patch.ToJson()); err != nil { + r, err := c.DoApiPut(c.GetRolesRoute()+fmt.Sprintf("/%v/patch", roleId), patch.ToJson()) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return RoleFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return RoleFromJson(r.Body), BuildResponse(r) } // Schemes Section // CreateScheme creates a new Scheme. func (c *Client4) CreateScheme(scheme *Scheme) (*Scheme, *Response) { - if r, err := c.DoApiPost(c.GetSchemesRoute(), scheme.ToJson()); err != nil { + r, err := c.DoApiPost(c.GetSchemesRoute(), scheme.ToJson()) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return SchemeFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return SchemeFromJson(r.Body), BuildResponse(r) } // GetScheme gets a single scheme by ID. func (c *Client4) GetScheme(id string) (*Scheme, *Response) { - if r, err := c.DoApiGet(c.GetSchemeRoute(id), ""); err != nil { + r, err := c.DoApiGet(c.GetSchemeRoute(id), "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return SchemeFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return SchemeFromJson(r.Body), BuildResponse(r) } -// Get all schemes, sorted with the most recently created first, optionally filtered by scope. +// GetSchemes gets all schemes, sorted with the most recently created first, optionally filtered by scope. func (c *Client4) GetSchemes(scope string, page int, perPage int) ([]*Scheme, *Response) { - if r, err := c.DoApiGet(c.GetSchemesRoute()+fmt.Sprintf("?scope=%v&page=%v&per_page=%v", scope, page, perPage), ""); err != nil { + r, err := c.DoApiGet(c.GetSchemesRoute()+fmt.Sprintf("?scope=%v&page=%v&per_page=%v", scope, page, perPage), "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return SchemesFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return SchemesFromJson(r.Body), BuildResponse(r) } // DeleteScheme deletes a single scheme by ID. func (c *Client4) DeleteScheme(id string) (bool, *Response) { - if r, err := c.DoApiDelete(c.GetSchemeRoute(id)); err != nil { + r, err := c.DoApiDelete(c.GetSchemeRoute(id)) + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } // PatchScheme partially updates a scheme in the system. Any missing fields are not updated. func (c *Client4) PatchScheme(id string, patch *SchemePatch) (*Scheme, *Response) { - if r, err := c.DoApiPut(c.GetSchemeRoute(id)+"/patch", patch.ToJson()); err != nil { + r, err := c.DoApiPut(c.GetSchemeRoute(id)+"/patch", patch.ToJson()) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return SchemeFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return SchemeFromJson(r.Body), BuildResponse(r) } -// Get the teams using this scheme, sorted alphabetically by display name. +// GetTeamsForScheme gets the teams using this scheme, sorted alphabetically by display name. func (c *Client4) GetTeamsForScheme(schemeId string, page int, perPage int) ([]*Team, *Response) { - if r, err := c.DoApiGet(c.GetSchemeRoute(schemeId)+fmt.Sprintf("/teams?page=%v&per_page=%v", page, perPage), ""); err != nil { + r, err := c.DoApiGet(c.GetSchemeRoute(schemeId)+fmt.Sprintf("/teams?page=%v&per_page=%v", page, perPage), "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return TeamListFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return TeamListFromJson(r.Body), BuildResponse(r) } -// Get the channels using this scheme, sorted alphabetically by display name. +// GetChannelsForScheme gets the channels using this scheme, sorted alphabetically by display name. func (c *Client4) GetChannelsForScheme(schemeId string, page int, perPage int) (ChannelList, *Response) { - if r, err := c.DoApiGet(c.GetSchemeRoute(schemeId)+fmt.Sprintf("/channels?page=%v&per_page=%v", page, perPage), ""); err != nil { + r, err := c.DoApiGet(c.GetSchemeRoute(schemeId)+fmt.Sprintf("/channels?page=%v&per_page=%v", page, perPage), "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return *ChannelListFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return *ChannelListFromJson(r.Body), BuildResponse(r) } // Plugin Section @@ -3747,13 +3786,16 @@ func (c *Client4) UploadPlugin(file io.Reader) (*Manifest, *Response) { body := new(bytes.Buffer) writer := multipart.NewWriter(body) - if part, err := writer.CreateFormFile("plugin", "plugin.tar.gz"); err != nil { - return nil, &Response{Error: NewAppError("UploadPlugin", "model.client.writer.app_error", nil, err.Error(), 0)} - } else if _, err = io.Copy(part, file); err != nil { + part, err := writer.CreateFormFile("plugin", "plugin.tar.gz") + if err != nil { return nil, &Response{Error: NewAppError("UploadPlugin", "model.client.writer.app_error", nil, err.Error(), 0)} } - if err := writer.Close(); err != nil { + if _, err = io.Copy(part, file); err != nil { + return nil, &Response{Error: NewAppError("UploadPlugin", "model.client.writer.app_error", nil, err.Error(), 0)} + } + + if err = writer.Close(); err != nil { return nil, &Response{Error: NewAppError("UploadPlugin", "model.client.writer.app_error", nil, err.Error(), 0)} } @@ -3764,161 +3806,157 @@ func (c *Client4) UploadPlugin(file io.Reader) (*Manifest, *Response) { rq.Header.Set(HEADER_AUTH, c.AuthType+" "+c.AuthToken) } - if rp, err := c.HttpClient.Do(rq); err != nil || rp == nil { + rp, err := c.HttpClient.Do(rq) + if err != nil || rp == nil { return nil, BuildErrorResponse(rp, NewAppError("UploadPlugin", "model.client.connecting.app_error", nil, err.Error(), 0)) - } else { - defer closeBody(rp) - - if rp.StatusCode >= 300 { - return nil, BuildErrorResponse(rp, AppErrorFromJson(rp.Body)) - } else { - return ManifestFromJson(rp.Body), BuildResponse(rp) - } } + defer closeBody(rp) + + if rp.StatusCode >= 300 { + return nil, BuildErrorResponse(rp, AppErrorFromJson(rp.Body)) + } + + return ManifestFromJson(rp.Body), BuildResponse(rp) } // GetPlugins will return a list of plugin manifests for currently active plugins. // WARNING: PLUGINS ARE STILL EXPERIMENTAL. THIS FUNCTION IS SUBJECT TO CHANGE. func (c *Client4) GetPlugins() (*PluginsResponse, *Response) { - if r, err := c.DoApiGet(c.GetPluginsRoute(), ""); err != nil { + r, err := c.DoApiGet(c.GetPluginsRoute(), "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return PluginsResponseFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return PluginsResponseFromJson(r.Body), BuildResponse(r) } // GetPluginStatuses will return the plugins installed on any server in the cluster, for reporting // to the administrator via the system console. // WARNING: PLUGINS ARE STILL EXPERIMENTAL. THIS FUNCTION IS SUBJECT TO CHANGE. func (c *Client4) GetPluginStatuses() (PluginStatuses, *Response) { - if r, err := c.DoApiGet(c.GetPluginsRoute(), "/statuses"); err != nil { + r, err := c.DoApiGet(c.GetPluginsRoute(), "/statuses") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return PluginStatusesFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return PluginStatusesFromJson(r.Body), BuildResponse(r) } // RemovePlugin will disable and delete a plugin. // WARNING: PLUGINS ARE STILL EXPERIMENTAL. THIS FUNCTION IS SUBJECT TO CHANGE. func (c *Client4) RemovePlugin(id string) (bool, *Response) { - if r, err := c.DoApiDelete(c.GetPluginRoute(id)); err != nil { + r, err := c.DoApiDelete(c.GetPluginRoute(id)) + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(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 { + r, err := c.DoApiGet(c.GetPluginsRoute()+"/webapp", "") + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return ManifestListFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return ManifestListFromJson(r.Body), BuildResponse(r) } // EnablePlugin will enable an plugin installed. // WARNING: PLUGINS ARE STILL EXPERIMENTAL. THIS FUNCTION IS SUBJECT TO CHANGE. func (c *Client4) EnablePlugin(id string) (bool, *Response) { - if r, err := c.DoApiPost(c.GetPluginRoute(id)+"/enable", ""); err != nil { + r, err := c.DoApiPost(c.GetPluginRoute(id)+"/enable", "") + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } // DisablePlugin will disable an enabled plugin. // WARNING: PLUGINS ARE STILL EXPERIMENTAL. THIS FUNCTION IS SUBJECT TO CHANGE. func (c *Client4) DisablePlugin(id string) (bool, *Response) { - if r, err := c.DoApiPost(c.GetPluginRoute(id)+"/disable", ""); err != nil { + r, err := c.DoApiPost(c.GetPluginRoute(id)+"/disable", "") + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } // UpdateChannelScheme will update a channel's scheme. func (c *Client4) UpdateChannelScheme(channelId, schemeId string) (bool, *Response) { sip := &SchemeIDPatch{SchemeID: &schemeId} - if r, err := c.DoApiPut(c.GetChannelSchemeRoute(channelId), sip.ToJson()); err != nil { + r, err := c.DoApiPut(c.GetChannelSchemeRoute(channelId), sip.ToJson()) + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } // UpdateTeamScheme will update a team's scheme. func (c *Client4) UpdateTeamScheme(teamId, schemeId string) (bool, *Response) { sip := &SchemeIDPatch{SchemeID: &schemeId} - if r, err := c.DoApiPut(c.GetTeamSchemeRoute(teamId), sip.ToJson()); err != nil { + r, err := c.DoApiPut(c.GetTeamSchemeRoute(teamId), sip.ToJson()) + if err != nil { return false, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) } + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) } // GetRedirectLocation retrieves the value of the 'Location' header of an HTTP response for a given URL. func (c *Client4) GetRedirectLocation(urlParam, etag string) (string, *Response) { url := fmt.Sprintf("%s?url=%s", c.GetRedirectLocationRoute(), url.QueryEscape(urlParam)) - if r, err := c.DoApiGet(url, etag); err != nil { + r, err := c.DoApiGet(url, etag) + if err != nil { return "", BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return MapFromJson(r.Body)["location"], BuildResponse(r) } + defer closeBody(r) + return MapFromJson(r.Body)["location"], BuildResponse(r) } func (c *Client4) RegisteTermsOfServiceAction(userId, termsOfServiceId string, accepted bool) (*bool, *Response) { url := c.GetUserTermsOfServiceRoute(userId) data := map[string]interface{}{"termsOfServiceId": termsOfServiceId, "accepted": accepted} - - if r, err := c.DoApiPost(url, StringInterfaceToJson(data)); err != nil { + r, err := c.DoApiPost(url, StringInterfaceToJson(data)) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return NewBool(CheckStatusOK(r)), BuildResponse(r) } + defer closeBody(r) + return NewBool(CheckStatusOK(r)), BuildResponse(r) } func (c *Client4) GetTermsOfService(etag string) (*TermsOfService, *Response) { url := c.GetTermsOfServiceRoute() - - if r, err := c.DoApiGet(url, etag); err != nil { + r, err := c.DoApiGet(url, etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return TermsOfServiceFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return TermsOfServiceFromJson(r.Body), BuildResponse(r) } func (c *Client4) GetUserTermsOfService(userId, etag string) (*UserTermsOfService, *Response) { url := c.GetUserTermsOfServiceRoute(userId) - - if r, err := c.DoApiGet(url, etag); err != nil { + r, err := c.DoApiGet(url, etag) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return UserTermsOfServiceFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return UserTermsOfServiceFromJson(r.Body), BuildResponse(r) } func (c *Client4) CreateTermsOfService(text, userId string) (*TermsOfService, *Response) { url := c.GetTermsOfServiceRoute() - data := map[string]interface{}{"text": text} - if r, err := c.DoApiPost(url, StringInterfaceToJson(data)); err != nil { + r, err := c.DoApiPost(url, StringInterfaceToJson(data)) + if err != nil { return nil, BuildErrorResponse(r, err) - } else { - defer closeBody(r) - return TermsOfServiceFromJson(r.Body), BuildResponse(r) } + defer closeBody(r) + return TermsOfServiceFromJson(r.Body), BuildResponse(r) } From 877e1b7f9ae59b840eafa082e6fe1c64e1db637b Mon Sep 17 00:00:00 2001 From: George Goldberg Date: Thu, 22 Nov 2018 11:19:47 +0000 Subject: [PATCH 09/10] MM-12957: Fix moving a channel with no members. (#9841) --- app/channel.go | 14 ++++++++------ app/channel_test.go | 21 +++++++++++++++++++-- 2 files changed, 27 insertions(+), 8 deletions(-) diff --git a/app/channel.go b/app/channel.go index 6e4f1b103a5..318ceb10cf9 100644 --- a/app/channel.go +++ b/app/channel.go @@ -1709,13 +1709,15 @@ func (a *App) MoveChannel(team *model.Team, channel *model.Channel, user *model. channelMemberIds = append(channelMemberIds, channelMember.UserId) } - teamMembers, err2 := a.GetTeamMembersByIds(team.Id, channelMemberIds) - if err2 != nil { - return err2 - } + if len(channelMemberIds) > 0 { + teamMembers, err2 := a.GetTeamMembersByIds(team.Id, channelMemberIds) + if err2 != nil { + return err2 + } - if len(teamMembers) != len(*channelMembers) { - return model.NewAppError("MoveChannel", "app.channel.move_channel.members_do_not_match.error", nil, "", http.StatusInternalServerError) + if len(teamMembers) != len(*channelMembers) { + return model.NewAppError("MoveChannel", "app.channel.move_channel.members_do_not_match.error", nil, "", http.StatusInternalServerError) + } } // keep instance of the previous team diff --git a/app/channel_test.go b/app/channel_test.go index 9acf8a709d4..d31318fe3de 100644 --- a/app/channel_test.go +++ b/app/channel_test.go @@ -8,10 +8,11 @@ import ( "strings" "testing" - "github.com/mattermost/mattermost-server/model" - "github.com/mattermost/mattermost-server/store" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + + "github.com/mattermost/mattermost-server/model" + "github.com/mattermost/mattermost-server/store" ) func TestPermanentDeleteChannel(t *testing.T) { @@ -138,6 +139,22 @@ func TestMoveChannel(t *testing.T) { if err := th.App.MoveChannel(targetTeam, channel2, th.BasicUser, true); err != nil { t.Fatal(err) } + + // Test moving a channel with no members. + channel3 := &model.Channel{ + DisplayName: "dn_" + model.NewId(), + Name: "name_" + model.NewId(), + Type: model.CHANNEL_OPEN, + TeamId: sourceTeam.Id, + CreatorId: th.BasicUser.Id, + } + + var err *model.AppError + channel3, err = th.App.CreateChannel(channel3, false) + require.Nil(t, err) + + err = th.App.MoveChannel(targetTeam, channel3, th.BasicUser, false) + assert.Nil(t, err) } func TestJoinDefaultChannelsCreatesChannelMemberHistoryRecordTownSquare(t *testing.T) { From d263353e852396373b3987f36a1445cecaf568a0 Mon Sep 17 00:00:00 2001 From: Elias Nahum Date: Thu, 22 Nov 2018 11:28:56 -0300 Subject: [PATCH 10/10] Typo (#9857) --- i18n/en.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/i18n/en.json b/i18n/en.json index 3cfcf35326c..0ae47d4e8d5 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -13,7 +13,7 @@ }, { "id": "interactive_message.generate_trigger_id.signing_failed", - "translation": "Failed to sign generatedd trigger ID for interactive dialog." + "translation": "Failed to sign generated trigger ID for interactive dialog." }, { "id": "interactive_message.decode_trigger_id.base64_decode_failed",