From 482a0fb5fc248b1ec61db35299dc3e6d963ad5ab Mon Sep 17 00:00:00 2001 From: Poornima Date: Sun, 12 Mar 2017 04:10:56 +0530 Subject: Adding functionality to get & delete incoming webhooks (#5648) --- api4/apitestlib.go | 8 ++++ api4/context.go | 12 ++++++ api4/context_test.go | 31 +++++++++++++++ api4/webhook.go | 75 +++++++++++++++++++++++++++++++++++ api4/webhook_test.go | 108 +++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 234 insertions(+) create mode 100644 api4/context_test.go (limited to 'api4') diff --git a/api4/apitestlib.go b/api4/apitestlib.go index 2647f20f6..3d2feaf6e 100644 --- a/api4/apitestlib.go +++ b/api4/apitestlib.go @@ -441,6 +441,14 @@ func CheckNotImplementedStatus(t *testing.T, resp *model.Response) { } } +func CheckOKStatus(t *testing.T, resp *model.Response) { + CheckNoError(t, resp) + + if resp.StatusCode != http.StatusOK { + t.Fatalf("wrong status code. expected %d got %d", http.StatusOK, resp.StatusCode) + } +} + func CheckErrorMessage(t *testing.T, resp *model.Response, errorId string) { if resp.Error == nil { debug.PrintStack() diff --git a/api4/context.go b/api4/context.go index c30a975f2..f9460f53b 100644 --- a/api4/context.go +++ b/api4/context.go @@ -455,3 +455,15 @@ func (c *Context) RequirePreferenceName() *Context { return c } + +func (c *Context) RequireHookId() *Context { + if c.Err != nil { + return c + } + + if len(c.Params.HookId) != 26 { + c.SetInvalidUrlParam("hook_id") + } + + return c +} diff --git a/api4/context_test.go b/api4/context_test.go new file mode 100644 index 000000000..302b7b24b --- /dev/null +++ b/api4/context_test.go @@ -0,0 +1,31 @@ +package api4 + +import ( + "net/http" + "testing" +) + +func TestRequireHookId(t *testing.T) { + c := &Context{} + t.Run("WhenHookIdIsValid", func(t *testing.T) { + c.Params = &ApiParams{HookId: "abcdefghijklmnopqrstuvwxyz"} + c.RequireHookId() + + if c.Err != nil { + t.Fatal("Hook Id is Valid. Should not have set error in context") + } + }) + + t.Run("WhenHookIdIsInvalid", func(t *testing.T) { + c.Params = &ApiParams{HookId: "abc"} + c.RequireHookId() + + if c.Err == nil { + t.Fatal("Should have set Error in context") + } + + if c.Err.StatusCode != http.StatusBadRequest { + t.Fatal("Should have set status as 400") + } + }) +} diff --git a/api4/webhook.go b/api4/webhook.go index 9efab6ae2..19a851390 100644 --- a/api4/webhook.go +++ b/api4/webhook.go @@ -17,6 +17,9 @@ func InitWebhook() { BaseRoutes.IncomingHooks.Handle("", ApiSessionRequired(createIncomingHook)).Methods("POST") BaseRoutes.IncomingHooks.Handle("", ApiSessionRequired(getIncomingHooks)).Methods("GET") + + BaseRoutes.IncomingHook.Handle("", ApiSessionRequired(getIncomingHook)).Methods("GET") + BaseRoutes.IncomingHook.Handle("", ApiSessionRequired(deleteIncomingHook)).Methods("DELETE") } func createIncomingHook(c *Context, w http.ResponseWriter, r *http.Request) { @@ -83,3 +86,75 @@ func getIncomingHooks(c *Context, w http.ResponseWriter, r *http.Request) { w.Write([]byte(model.IncomingWebhookListToJson(hooks))) } + +func getIncomingHook(c *Context, w http.ResponseWriter, r *http.Request) { + c.RequireHookId() + if c.Err != nil { + return + } + + hookID := c.Params.HookId + + var err *model.AppError + var hook *model.IncomingWebhook + var channel *model.Channel + + if hook, err = app.GetIncomingWebhook(hookID); err != nil { + c.Err = err + return + } else { + channel, err = app.GetChannel(hook.ChannelId) + if err != nil { + c.Err = err + return + } + + if !app.SessionHasPermissionToTeam(c.Session, hook.TeamId, model.PERMISSION_MANAGE_WEBHOOKS) || + (channel.Type != model.CHANNEL_OPEN && !app.SessionHasPermissionToChannel(c.Session, hook.ChannelId, model.PERMISSION_READ_CHANNEL)) { + c.LogAudit("fail - bad permissions") + c.SetPermissionError(model.PERMISSION_MANAGE_WEBHOOKS) + return + } else { + w.Write([]byte(hook.ToJson())) + return + } + } +} + +func deleteIncomingHook(c *Context, w http.ResponseWriter, r *http.Request) { + c.RequireHookId() + if c.Err != nil { + return + } + + hookID := c.Params.HookId + + var err *model.AppError + var hook *model.IncomingWebhook + var channel *model.Channel + + if hook, err = app.GetIncomingWebhook(hookID); err != nil { + c.Err = err + return + } else { + channel, err = app.GetChannel(hook.ChannelId) + if err != nil { + c.Err = err + return + } + + if !app.SessionHasPermissionToTeam(c.Session, hook.TeamId, model.PERMISSION_MANAGE_WEBHOOKS) || + (channel.Type != model.CHANNEL_OPEN && !app.SessionHasPermissionToChannel(c.Session, hook.ChannelId, model.PERMISSION_READ_CHANNEL)) { + c.LogAudit("fail - bad permissions") + c.SetPermissionError(model.PERMISSION_MANAGE_WEBHOOKS) + return + } else { + if err = app.DeleteIncomingWebhook(hookID); err != nil { + c.Err = err + return + } + + ReturnStatusOK(w) + } + } +} diff --git a/api4/webhook_test.go b/api4/webhook_test.go index a6705f6e1..bfd75c7ec 100644 --- a/api4/webhook_test.go +++ b/api4/webhook_test.go @@ -148,3 +148,111 @@ func TestGetIncomingWebhooks(t *testing.T) { _, resp = Client.GetIncomingWebhooks(0, 1000, "") CheckUnauthorizedStatus(t, resp) } + +func TestGetIncomingWebhook(t *testing.T) { + th := Setup().InitBasic().InitSystemAdmin() + defer TearDown() + Client := th.SystemAdminClient + + enableIncomingHooks := utils.Cfg.ServiceSettings.EnableIncomingWebhooks + enableAdminOnlyHooks := utils.Cfg.ServiceSettings.EnableOnlyAdminIntegrations + defer func() { + utils.Cfg.ServiceSettings.EnableIncomingWebhooks = enableIncomingHooks + utils.Cfg.ServiceSettings.EnableOnlyAdminIntegrations = enableAdminOnlyHooks + utils.SetDefaultRolesBasedOnConfig() + }() + utils.Cfg.ServiceSettings.EnableIncomingWebhooks = true + *utils.Cfg.ServiceSettings.EnableOnlyAdminIntegrations = true + utils.SetDefaultRolesBasedOnConfig() + + var resp *model.Response + var rhook *model.IncomingWebhook + var hook *model.IncomingWebhook + + t.Run("WhenHookExists", func(t *testing.T) { + hook = &model.IncomingWebhook{ChannelId: th.BasicChannel.Id} + rhook, resp = Client.CreateIncomingWebhook(hook) + CheckNoError(t, resp) + + hook, resp = Client.GetIncomingWebhook(rhook.Id, "") + CheckOKStatus(t, resp) + }) + + t.Run("WhenHookDoesNotExist", func(t *testing.T) { + hook, resp = Client.GetIncomingWebhook(model.NewId(), "") + CheckNotFoundStatus(t, resp) + }) + + t.Run("WhenInvalidHookID", func(t *testing.T) { + hook, resp = Client.GetIncomingWebhook("abc", "") + CheckBadRequestStatus(t, resp) + }) + + t.Run("WhenUserDoesNotHavePemissions", func(t *testing.T) { + th.LoginBasic() + Client = th.Client + + _, resp = Client.GetIncomingWebhook(rhook.Id, "") + CheckForbiddenStatus(t, resp) + }) +} + +func TestDeleteIncomingWebhook(t *testing.T) { + th := Setup().InitBasic().InitSystemAdmin() + defer TearDown() + Client := th.SystemAdminClient + + enableIncomingHooks := utils.Cfg.ServiceSettings.EnableIncomingWebhooks + enableAdminOnlyHooks := utils.Cfg.ServiceSettings.EnableOnlyAdminIntegrations + defer func() { + utils.Cfg.ServiceSettings.EnableIncomingWebhooks = enableIncomingHooks + utils.Cfg.ServiceSettings.EnableOnlyAdminIntegrations = enableAdminOnlyHooks + utils.SetDefaultRolesBasedOnConfig() + }() + utils.Cfg.ServiceSettings.EnableIncomingWebhooks = true + *utils.Cfg.ServiceSettings.EnableOnlyAdminIntegrations = true + utils.SetDefaultRolesBasedOnConfig() + + var resp *model.Response + var rhook *model.IncomingWebhook + var hook *model.IncomingWebhook + var status bool + + t.Run("WhenInvalidHookID", func(t *testing.T) { + status, resp = Client.DeleteIncomingWebhook("abc") + CheckBadRequestStatus(t, resp) + }) + + t.Run("WhenHookDoesNotExist", func(t *testing.T) { + status, resp = Client.DeleteIncomingWebhook(model.NewId()) + CheckNotFoundStatus(t, resp) + }) + + t.Run("WhenHookExists", func(t *testing.T) { + hook = &model.IncomingWebhook{ChannelId: th.BasicChannel.Id} + rhook, resp = Client.CreateIncomingWebhook(hook) + CheckNoError(t, resp) + + if status, resp = Client.DeleteIncomingWebhook(rhook.Id); !status { + t.Fatal("Delete should have succeeded") + } else { + CheckOKStatus(t, resp) + } + + // Get now should not return this deleted hook + _, resp = Client.GetIncomingWebhook(rhook.Id, "") + CheckNotFoundStatus(t, resp) + }) + + t.Run("WhenUserDoesNotHavePemissions", func(t *testing.T) { + hook = &model.IncomingWebhook{ChannelId: th.BasicChannel.Id} + rhook, resp = Client.CreateIncomingWebhook(hook) + CheckNoError(t, resp) + + th.LoginBasic() + Client = th.Client + + _, resp = Client.DeleteIncomingWebhook(rhook.Id) + CheckForbiddenStatus(t, resp) + }) +} -- cgit v1.2.3-1-g7c22