From 09dbd6be0d1a7eda7ba3a7b2f91b1515535b49bb Mon Sep 17 00:00:00 2001 From: James Lakin Date: Sat, 29 Feb 2020 19:14:56 +0000 Subject: [PATCH 01/15] Create system webhook column (and migration) --- models/migrations/migrations.go | 2 ++ models/migrations/v128.go | 22 ++++++++++++++++++++++ models/webhook.go | 31 ++++++++++++++++--------------- 3 files changed, 40 insertions(+), 15 deletions(-) create mode 100644 models/migrations/v128.go diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go index ce3f77ba4e26f..66923fd50f770 100644 --- a/models/migrations/migrations.go +++ b/models/migrations/migrations.go @@ -188,6 +188,8 @@ var migrations = []Migration{ NewMigration("Fix topic repository count", fixTopicRepositoryCount), // v127 -> v128 NewMigration("add repository code language statistics", addLanguageStats), + // v128 -> v129 + NewMigration("Add IsSystemWebhook column to webhooks table", addSystemWebhookColumn), } // Migrate database to current version diff --git a/models/migrations/v128.go b/models/migrations/v128.go new file mode 100644 index 0000000000000..5a7caf582a166 --- /dev/null +++ b/models/migrations/v128.go @@ -0,0 +1,22 @@ +// Copyright 2020 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package migrations + +import ( + "fmt" + + "xorm.io/xorm" +) + +func addSystemWebhookColumn(x *xorm.Engine) error { + type Webhook struct { + IsSystemWebhook bool `xorm:"NOT NULL DEFAULT 0"` + } + + if err := x.Sync2(new(Webhook)); err != nil { + return fmt.Errorf("Sync2: %v", err) + } + return nil +} diff --git a/models/webhook.go b/models/webhook.go index 626489b342e44..f55f93529a78e 100644 --- a/models/webhook.go +++ b/models/webhook.go @@ -90,21 +90,22 @@ const ( // Webhook represents a web hook object. type Webhook struct { - ID int64 `xorm:"pk autoincr"` - RepoID int64 `xorm:"INDEX"` - OrgID int64 `xorm:"INDEX"` - URL string `xorm:"url TEXT"` - Signature string `xorm:"TEXT"` - HTTPMethod string `xorm:"http_method"` - ContentType HookContentType - Secret string `xorm:"TEXT"` - Events string `xorm:"TEXT"` - *HookEvent `xorm:"-"` - IsSSL bool `xorm:"is_ssl"` - IsActive bool `xorm:"INDEX"` - HookTaskType HookTaskType - Meta string `xorm:"TEXT"` // store hook-specific attributes - LastStatus HookStatus // Last delivery status + ID int64 `xorm:"pk autoincr"` + RepoID int64 `xorm:"INDEX"` // An ID of 0 indicates either a default or system webhook + OrgID int64 `xorm:"INDEX"` + IsSystemWebhook bool + URL string `xorm:"url TEXT"` + Signature string `xorm:"TEXT"` + HTTPMethod string `xorm:"http_method"` + ContentType HookContentType + Secret string `xorm:"TEXT"` + Events string `xorm:"TEXT"` + *HookEvent `xorm:"-"` + IsSSL bool `xorm:"is_ssl"` + IsActive bool `xorm:"INDEX"` + HookTaskType HookTaskType + Meta string `xorm:"TEXT"` // store hook-specific attributes + LastStatus HookStatus // Last delivery status CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"` UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"` From 1decbb5b2764f700f393d0f69d1bc237ed0f0731 Mon Sep 17 00:00:00 2001 From: James Lakin Date: Sat, 29 Feb 2020 20:57:51 +0000 Subject: [PATCH 02/15] Create system webhook DB methods Based on the default webhook ones --- models/webhook.go | 32 +++++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/models/webhook.go b/models/webhook.go index f55f93529a78e..cf4764c7c2555 100644 --- a/models/webhook.go +++ b/models/webhook.go @@ -316,7 +316,7 @@ func GetWebhooksByOrgID(orgID int64, listOptions ListOptions) ([]*Webhook, error func GetDefaultWebhook(id int64) (*Webhook, error) { webhook := &Webhook{ID: id} has, err := x. - Where("repo_id=? AND org_id=?", 0, 0). + Where("repo_id=? AND org_id=? AND is_system_webhook=?", 0, 0, 0). Get(webhook) if err != nil { return nil, err @@ -334,7 +334,33 @@ func GetDefaultWebhooks() ([]*Webhook, error) { func getDefaultWebhooks(e Engine) ([]*Webhook, error) { webhooks := make([]*Webhook, 0, 5) return webhooks, e. - Where("repo_id=? AND org_id=?", 0, 0). + Where("repo_id=? AND org_id=? AND is_system_webhook=?", 0, 0, 0). + Find(&webhooks) +} + +// GetSystemWebhook returns admin system webhook by given ID. +func GetSystemWebhook(id int64) (*Webhook, error) { + webhook := &Webhook{ID: id} + has, err := x. + Where("repo_id=? AND org_id=? AND is_system_webhook=?", 0, 0, 1). + Get(webhook) + if err != nil { + return nil, err + } else if !has { + return nil, ErrWebhookNotExist{id} + } + return webhook, nil +} + +// GetSystemWebhooks returns all admin system webhooks. +func GetSystemWebhooks() ([]*Webhook, error) { + return getSystemWebhooks(x) +} + +func getSystemWebhooks(e Engine) ([]*Webhook, error) { + webhooks := make([]*Webhook, 0, 5) + return webhooks, e. + Where("repo_id=? AND org_id=? AND is_system_webhook=?", 0, 0, 1). Find(&webhooks) } @@ -395,7 +421,7 @@ func DeleteDefaultWebhook(id int64) error { } count, err := sess. - Where("repo_id=? AND org_id=?", 0, 0). + Where("repo_id=? AND org_id=? AND is_system_webhook=?", 0, 0, 0). Delete(&Webhook{ID: id}) if err != nil { return err From c35b7acafa1af93764bb6aaef14bce725d859145 Mon Sep 17 00:00:00 2001 From: James Lakin Date: Sat, 29 Feb 2020 20:58:39 +0000 Subject: [PATCH 03/15] Modify router to handle system webhooks and default ones --- routers/admin/hooks.go | 26 +++++++++++++++++++------- routers/routes/routes.go | 4 ++-- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/routers/admin/hooks.go b/routers/admin/hooks.go index b80ed3cc3c5ec..1b96150b0b90b 100644 --- a/routers/admin/hooks.go +++ b/routers/admin/hooks.go @@ -5,6 +5,8 @@ package admin import ( + "strings" + "code.gitea.io/gitea/models" "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/context" @@ -12,20 +14,30 @@ import ( ) const ( - // tplAdminHooks template path for render hook settings + // tplAdminHooks template path to render hook settings tplAdminHooks base.TplName = "admin/hooks" ) -// DefaultWebhooks render admin-default webhook list page -func DefaultWebhooks(ctx *context.Context) { +// DefaultAndSystemWebhooks renders both admin default and system webhook list pages +func DefaultAndSystemWebhooks(ctx *context.Context) { ctx.Data["Title"] = ctx.Tr("admin.hooks") - ctx.Data["PageIsAdminHooks"] = true - ctx.Data["BaseLink"] = setting.AppSubURL + "/admin/hooks" ctx.Data["Description"] = ctx.Tr("admin.hooks.desc") - ws, err := models.GetDefaultWebhooks() + // Are we looking at default webhooks? + var ws []*models.Webhook + var err error + if strings.Contains(ctx.Link, "/admin/hooks") { + ctx.Data["PageIsAdminHooks"] = true + ctx.Data["BaseLink"] = setting.AppSubURL + "/admin/hooks" + ws, err = models.GetDefaultWebhooks() + } else { + ctx.Data["PageIsAdminSystemHooks"] = true + ctx.Data["BaseLink"] = setting.AppSubURL + "/admin/system-hooks" + ws, err = models.GetSystemWebhooks() + } + if err != nil { - ctx.ServerError("GetWebhooksDefaults", err) + ctx.ServerError("GetWebhooksAdmin", err) return } diff --git a/routers/routes/routes.go b/routers/routes/routes.go index 9859ebc539384..7123e092f1465 100644 --- a/routers/routes/routes.go +++ b/routers/routes/routes.go @@ -453,8 +453,8 @@ func RegisterRoutes(m *macaron.Macaron) { m.Post("/delete", admin.DeleteRepo) }) - m.Group("/hooks", func() { - m.Get("", admin.DefaultWebhooks) + m.Group("/^:type(hooks|system-hooks)$", func() { + m.Get("", admin.DefaultAndSystemWebhooks) m.Post("/delete", admin.DeleteDefaultWebhook) m.Get("/:type/new", repo.WebhooksNew) m.Post("/gitea/new", bindIgnErr(auth.NewWebhookForm{}), repo.WebHooksNewPost) From 191a20a7389fe5f6256b0ad6aafd04b9b0e295c5 Mon Sep 17 00:00:00 2001 From: James Lakin Date: Sat, 29 Feb 2020 20:58:58 +0000 Subject: [PATCH 04/15] Remove old unused admin nav template --- templates/admin/nav.tmpl | 16 ---------------- 1 file changed, 16 deletions(-) delete mode 100644 templates/admin/nav.tmpl diff --git a/templates/admin/nav.tmpl b/templates/admin/nav.tmpl deleted file mode 100644 index d95a0d7ecfb49..0000000000000 --- a/templates/admin/nav.tmpl +++ /dev/null @@ -1,16 +0,0 @@ - From 47c687cb1adb66ffc6f4d61144ab539d2c26596f Mon Sep 17 00:00:00 2001 From: James Lakin Date: Sat, 29 Feb 2020 21:01:40 +0000 Subject: [PATCH 05/15] Adjust orgRepoCtx to differentiate system and default webhook URLs --- routers/repo/webhook.go | 37 ++++++++++++++++++++++++++++++------- 1 file changed, 30 insertions(+), 7 deletions(-) diff --git a/routers/repo/webhook.go b/routers/repo/webhook.go index 009a9e223caf4..b7bc2f0db17b3 100644 --- a/routers/repo/webhook.go +++ b/routers/repo/webhook.go @@ -49,14 +49,15 @@ func Webhooks(ctx *context.Context) { } type orgRepoCtx struct { - OrgID int64 - RepoID int64 - IsAdmin bool - Link string - NewTemplate base.TplName + OrgID int64 + RepoID int64 + IsAdmin bool + IsSystemWebhook bool + Link string + NewTemplate base.TplName } -// getOrgRepoCtx determines whether this is a repo, organization, or admin context. +// getOrgRepoCtx determines whether this is a repo, organization, or admin (both default and system) context. func getOrgRepoCtx(ctx *context.Context) (*orgRepoCtx, error) { if len(ctx.Repo.RepoLink) > 0 { return &orgRepoCtx{ @@ -75,6 +76,8 @@ func getOrgRepoCtx(ctx *context.Context) (*orgRepoCtx, error) { } if ctx.User.IsAdmin { + // Are we looking at default webhooks? + if strings.Contains(ctx.Link, "/admin/hooks") { return &orgRepoCtx{ IsAdmin: true, Link: path.Join(setting.AppSubURL, "/admin/hooks"), @@ -82,6 +85,15 @@ func getOrgRepoCtx(ctx *context.Context) (*orgRepoCtx, error) { }, nil } + // Must be system webhooks instead + return &orgRepoCtx{ + IsAdmin: true, + IsSystemWebhook: true, + Link: path.Join(setting.AppSubURL, "/admin/system-hooks"), + NewTemplate: tplAdminHookNew, + }, nil + } + return nil, errors.New("Unable to set OrgRepo context") } @@ -105,7 +117,10 @@ func WebhooksNew(ctx *context.Context) { return } - if orCtx.IsAdmin { + if orCtx.IsAdmin && orCtx.IsSystemWebhook { + ctx.Data["PageIsAdminSystemHooks"] = true + ctx.Data["PageIsAdminSystemHooksNew"] = true + } else if orCtx.IsAdmin { ctx.Data["PageIsAdminHooks"] = true ctx.Data["PageIsAdminHooksNew"] = true } else { @@ -535,11 +550,19 @@ func checkWebhook(ctx *context.Context) (*orgRepoCtx, *models.Webhook) { } ctx.Data["BaseLink"] = orCtx.Link + // Used to inform the admin template the difference between default and system webhooks + if orCtx.IsSystemWebhook { + ctx.Data["IsSystemWebhook"] = true + } + var w *models.Webhook + // Why different methods if only the ID matters? if orCtx.RepoID > 0 { w, err = models.GetWebhookByRepoID(ctx.Repo.Repository.ID, ctx.ParamsInt64(":id")) } else if orCtx.OrgID > 0 { w, err = models.GetWebhookByOrgID(ctx.Org.Organization.ID, ctx.ParamsInt64(":id")) + } else if orCtx.IsSystemWebhook { + w, err = models.GetSystemWebhook(ctx.ParamsInt64(":id")) } else { w, err = models.GetDefaultWebhook(ctx.ParamsInt64(":id")) } From 59a2e556d1b64a1c8dc70035880a2896e7cb0f05 Mon Sep 17 00:00:00 2001 From: James Lakin Date: Sat, 29 Feb 2020 21:03:08 +0000 Subject: [PATCH 06/15] Assign IsSystemWebhook when creating webhooks --- routers/repo/webhook.go | 152 +++++++++++++++++++++------------------- 1 file changed, 80 insertions(+), 72 deletions(-) diff --git a/routers/repo/webhook.go b/routers/repo/webhook.go index b7bc2f0db17b3..ce3ba537d5241 100644 --- a/routers/repo/webhook.go +++ b/routers/repo/webhook.go @@ -78,12 +78,12 @@ func getOrgRepoCtx(ctx *context.Context) (*orgRepoCtx, error) { if ctx.User.IsAdmin { // Are we looking at default webhooks? if strings.Contains(ctx.Link, "/admin/hooks") { - return &orgRepoCtx{ - IsAdmin: true, - Link: path.Join(setting.AppSubURL, "/admin/hooks"), - NewTemplate: tplAdminHookNew, - }, nil - } + return &orgRepoCtx{ + IsAdmin: true, + Link: path.Join(setting.AppSubURL, "/admin/hooks"), + NewTemplate: tplAdminHookNew, + }, nil + } // Must be system webhooks instead return &orgRepoCtx{ @@ -165,7 +165,7 @@ func ParseHookEvent(form auth.WebhookForm) *models.HookEvent { } } -// WebHooksNewPost response for creating webhook +// WebHooksNewPost response for creating Gitea webhook func WebHooksNewPost(ctx *context.Context, form auth.NewWebhookForm) { ctx.Data["Title"] = ctx.Tr("repo.settings.add_webhook") ctx.Data["PageIsSettingsHooks"] = true @@ -191,15 +191,16 @@ func WebHooksNewPost(ctx *context.Context, form auth.NewWebhookForm) { } w := &models.Webhook{ - RepoID: orCtx.RepoID, - URL: form.PayloadURL, - HTTPMethod: form.HTTPMethod, - ContentType: contentType, - Secret: form.Secret, - HookEvent: ParseHookEvent(form.WebhookForm), - IsActive: form.Active, - HookTaskType: models.GITEA, - OrgID: orCtx.OrgID, + RepoID: orCtx.RepoID, + URL: form.PayloadURL, + HTTPMethod: form.HTTPMethod, + ContentType: contentType, + Secret: form.Secret, + HookEvent: ParseHookEvent(form.WebhookForm), + IsActive: form.Active, + HookTaskType: models.GITEA, + OrgID: orCtx.OrgID, + IsSystemWebhook: orCtx.IsSystemWebhook, } if err := w.UpdateEvent(); err != nil { ctx.ServerError("UpdateEvent", err) @@ -244,14 +245,15 @@ func newGogsWebhookPost(ctx *context.Context, form auth.NewGogshookForm, kind mo } w := &models.Webhook{ - RepoID: orCtx.RepoID, - URL: form.PayloadURL, - ContentType: contentType, - Secret: form.Secret, - HookEvent: ParseHookEvent(form.WebhookForm), - IsActive: form.Active, - HookTaskType: kind, - OrgID: orCtx.OrgID, + RepoID: orCtx.RepoID, + URL: form.PayloadURL, + ContentType: contentType, + Secret: form.Secret, + HookEvent: ParseHookEvent(form.WebhookForm), + IsActive: form.Active, + HookTaskType: kind, + OrgID: orCtx.OrgID, + IsSystemWebhook: orCtx.IsSystemWebhook, } if err := w.UpdateEvent(); err != nil { ctx.ServerError("UpdateEvent", err) @@ -293,14 +295,15 @@ func DiscordHooksNewPost(ctx *context.Context, form auth.NewDiscordHookForm) { } w := &models.Webhook{ - RepoID: orCtx.RepoID, - URL: form.PayloadURL, - ContentType: models.ContentTypeJSON, - HookEvent: ParseHookEvent(form.WebhookForm), - IsActive: form.Active, - HookTaskType: models.DISCORD, - Meta: string(meta), - OrgID: orCtx.OrgID, + RepoID: orCtx.RepoID, + URL: form.PayloadURL, + ContentType: models.ContentTypeJSON, + HookEvent: ParseHookEvent(form.WebhookForm), + IsActive: form.Active, + HookTaskType: models.DISCORD, + Meta: string(meta), + OrgID: orCtx.OrgID, + IsSystemWebhook: orCtx.IsSystemWebhook, } if err := w.UpdateEvent(); err != nil { ctx.ServerError("UpdateEvent", err) @@ -333,14 +336,15 @@ func DingtalkHooksNewPost(ctx *context.Context, form auth.NewDingtalkHookForm) { } w := &models.Webhook{ - RepoID: orCtx.RepoID, - URL: form.PayloadURL, - ContentType: models.ContentTypeJSON, - HookEvent: ParseHookEvent(form.WebhookForm), - IsActive: form.Active, - HookTaskType: models.DINGTALK, - Meta: "", - OrgID: orCtx.OrgID, + RepoID: orCtx.RepoID, + URL: form.PayloadURL, + ContentType: models.ContentTypeJSON, + HookEvent: ParseHookEvent(form.WebhookForm), + IsActive: form.Active, + HookTaskType: models.DINGTALK, + Meta: "", + OrgID: orCtx.OrgID, + IsSystemWebhook: orCtx.IsSystemWebhook, } if err := w.UpdateEvent(); err != nil { ctx.ServerError("UpdateEvent", err) @@ -382,14 +386,15 @@ func TelegramHooksNewPost(ctx *context.Context, form auth.NewTelegramHookForm) { } w := &models.Webhook{ - RepoID: orCtx.RepoID, - URL: fmt.Sprintf("https://api.telegram.org/bot%s/sendMessage?chat_id=%s", form.BotToken, form.ChatID), - ContentType: models.ContentTypeJSON, - HookEvent: ParseHookEvent(form.WebhookForm), - IsActive: form.Active, - HookTaskType: models.TELEGRAM, - Meta: string(meta), - OrgID: orCtx.OrgID, + RepoID: orCtx.RepoID, + URL: fmt.Sprintf("https://api.telegram.org/bot%s/sendMessage?chat_id=%s", form.BotToken, form.ChatID), + ContentType: models.ContentTypeJSON, + HookEvent: ParseHookEvent(form.WebhookForm), + IsActive: form.Active, + HookTaskType: models.TELEGRAM, + Meta: string(meta), + OrgID: orCtx.OrgID, + IsSystemWebhook: orCtx.IsSystemWebhook, } if err := w.UpdateEvent(); err != nil { ctx.ServerError("UpdateEvent", err) @@ -422,14 +427,15 @@ func MSTeamsHooksNewPost(ctx *context.Context, form auth.NewMSTeamsHookForm) { } w := &models.Webhook{ - RepoID: orCtx.RepoID, - URL: form.PayloadURL, - ContentType: models.ContentTypeJSON, - HookEvent: ParseHookEvent(form.WebhookForm), - IsActive: form.Active, - HookTaskType: models.MSTEAMS, - Meta: "", - OrgID: orCtx.OrgID, + RepoID: orCtx.RepoID, + URL: form.PayloadURL, + ContentType: models.ContentTypeJSON, + HookEvent: ParseHookEvent(form.WebhookForm), + IsActive: form.Active, + HookTaskType: models.MSTEAMS, + Meta: "", + OrgID: orCtx.OrgID, + IsSystemWebhook: orCtx.IsSystemWebhook, } if err := w.UpdateEvent(); err != nil { ctx.ServerError("UpdateEvent", err) @@ -479,14 +485,15 @@ func SlackHooksNewPost(ctx *context.Context, form auth.NewSlackHookForm) { } w := &models.Webhook{ - RepoID: orCtx.RepoID, - URL: form.PayloadURL, - ContentType: models.ContentTypeJSON, - HookEvent: ParseHookEvent(form.WebhookForm), - IsActive: form.Active, - HookTaskType: models.SLACK, - Meta: string(meta), - OrgID: orCtx.OrgID, + RepoID: orCtx.RepoID, + URL: form.PayloadURL, + ContentType: models.ContentTypeJSON, + HookEvent: ParseHookEvent(form.WebhookForm), + IsActive: form.Active, + HookTaskType: models.SLACK, + Meta: string(meta), + OrgID: orCtx.OrgID, + IsSystemWebhook: orCtx.IsSystemWebhook, } if err := w.UpdateEvent(); err != nil { ctx.ServerError("UpdateEvent", err) @@ -519,14 +526,15 @@ func FeishuHooksNewPost(ctx *context.Context, form auth.NewFeishuHookForm) { } w := &models.Webhook{ - RepoID: orCtx.RepoID, - URL: form.PayloadURL, - ContentType: models.ContentTypeJSON, - HookEvent: ParseHookEvent(form.WebhookForm), - IsActive: form.Active, - HookTaskType: models.FEISHU, - Meta: "", - OrgID: orCtx.OrgID, + RepoID: orCtx.RepoID, + URL: form.PayloadURL, + ContentType: models.ContentTypeJSON, + HookEvent: ParseHookEvent(form.WebhookForm), + IsActive: form.Active, + HookTaskType: models.FEISHU, + Meta: "", + OrgID: orCtx.OrgID, + IsSystemWebhook: orCtx.IsSystemWebhook, } if err := w.UpdateEvent(); err != nil { ctx.ServerError("UpdateEvent", err) From e03dc4a9cee5ce8af60d3b7aee5159f314a9c458 Mon Sep 17 00:00:00 2001 From: James Lakin Date: Sat, 29 Feb 2020 22:09:48 +0000 Subject: [PATCH 07/15] Correctly use booleans for IsSystemWebhook --- models/migrations/v128.go | 2 +- models/webhook.go | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/models/migrations/v128.go b/models/migrations/v128.go index 5a7caf582a166..a38c7be634ff5 100644 --- a/models/migrations/v128.go +++ b/models/migrations/v128.go @@ -12,7 +12,7 @@ import ( func addSystemWebhookColumn(x *xorm.Engine) error { type Webhook struct { - IsSystemWebhook bool `xorm:"NOT NULL DEFAULT 0"` + IsSystemWebhook bool `xorm:"NOT NULL DEFAULT false"` } if err := x.Sync2(new(Webhook)); err != nil { diff --git a/models/webhook.go b/models/webhook.go index cf4764c7c2555..f5a823d09b0d7 100644 --- a/models/webhook.go +++ b/models/webhook.go @@ -316,7 +316,7 @@ func GetWebhooksByOrgID(orgID int64, listOptions ListOptions) ([]*Webhook, error func GetDefaultWebhook(id int64) (*Webhook, error) { webhook := &Webhook{ID: id} has, err := x. - Where("repo_id=? AND org_id=? AND is_system_webhook=?", 0, 0, 0). + Where("repo_id=? AND org_id=? AND is_system_webhook=?", 0, 0, false). Get(webhook) if err != nil { return nil, err @@ -334,7 +334,7 @@ func GetDefaultWebhooks() ([]*Webhook, error) { func getDefaultWebhooks(e Engine) ([]*Webhook, error) { webhooks := make([]*Webhook, 0, 5) return webhooks, e. - Where("repo_id=? AND org_id=? AND is_system_webhook=?", 0, 0, 0). + Where("repo_id=? AND org_id=? AND is_system_webhook=?", 0, 0, false). Find(&webhooks) } @@ -342,7 +342,7 @@ func getDefaultWebhooks(e Engine) ([]*Webhook, error) { func GetSystemWebhook(id int64) (*Webhook, error) { webhook := &Webhook{ID: id} has, err := x. - Where("repo_id=? AND org_id=? AND is_system_webhook=?", 0, 0, 1). + Where("repo_id=? AND org_id=? AND is_system_webhook=?", 0, 0, true). Get(webhook) if err != nil { return nil, err @@ -360,7 +360,7 @@ func GetSystemWebhooks() ([]*Webhook, error) { func getSystemWebhooks(e Engine) ([]*Webhook, error) { webhooks := make([]*Webhook, 0, 5) return webhooks, e. - Where("repo_id=? AND org_id=? AND is_system_webhook=?", 0, 0, 1). + Where("repo_id=? AND org_id=? AND is_system_webhook=?", 0, 0, true). Find(&webhooks) } @@ -421,7 +421,7 @@ func DeleteDefaultWebhook(id int64) error { } count, err := sess. - Where("repo_id=? AND org_id=? AND is_system_webhook=?", 0, 0, 0). + Where("repo_id=? AND org_id=? AND is_system_webhook=?", 0, 0, false). Delete(&Webhook{ID: id}) if err != nil { return err From d3975209741afd934455ec0968277f80e02ef1ff Mon Sep 17 00:00:00 2001 From: James Lakin Date: Sun, 1 Mar 2020 09:02:49 +0000 Subject: [PATCH 08/15] Use system webhooks when preparing webhooks for payload --- modules/webhook/webhook.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/modules/webhook/webhook.go b/modules/webhook/webhook.go index 2fab0803bc37d..75a81d2aff9a3 100644 --- a/modules/webhook/webhook.go +++ b/modules/webhook/webhook.go @@ -181,6 +181,13 @@ func prepareWebhooks(repo *models.Repository, event models.HookEventType, p api. ws = append(ws, orgHooks...) } + // Add any admin-defined system webhooks + systemHooks, err := models.GetSystemWebhooks() + if err != nil { + return fmt.Errorf("GetSystemWebhooks: %v", err) + } + ws = append(ws, systemHooks...) + if len(ws) == 0 { return nil } From 4de383406d19dd6e84e7cbc1bd00813a82ae9fd0 Mon Sep 17 00:00:00 2001 From: James Lakin Date: Sun, 1 Mar 2020 09:30:42 +0000 Subject: [PATCH 09/15] Add UI and locale changes --- options/locale/locale_en-US.ini | 5 +++++ routers/admin/hooks.go | 10 ++++++---- routers/repo/webhook.go | 5 ----- templates/admin/navbar.tmpl | 3 +++ 4 files changed, 14 insertions(+), 9 deletions(-) diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index 4a38dc62c1fbd..323b0eaed3893 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -1723,6 +1723,7 @@ users = User Accounts organizations = Organizations repositories = Repositories hooks = Default Webhooks +systemhooks = System Webhooks authentication = Authentication Sources config = Configuration notices = System Notices @@ -1844,6 +1845,10 @@ hooks.desc = Webhooks automatically make HTTP POST requests to a server when cer hooks.add_webhook = Add Default Webhook hooks.update_webhook = Update Default Webhook +systemhooks.desc = Webhooks automatically make HTTP POST requests to a server when certain Gitea events trigger. Webhooks defined will act on all repositories on the system, so please consider any performance implications this may have. Read more in the webhooks guide. +systemhooks.add_webhook = Add System Webhook +systemhooks.update_webhook = Update System Webhook + auths.auth_manage_panel = Authentication Source Management auths.new = Add Authentication Source auths.name = Name diff --git a/routers/admin/hooks.go b/routers/admin/hooks.go index 1b96150b0b90b..535bb75132519 100644 --- a/routers/admin/hooks.go +++ b/routers/admin/hooks.go @@ -20,17 +20,19 @@ const ( // DefaultAndSystemWebhooks renders both admin default and system webhook list pages func DefaultAndSystemWebhooks(ctx *context.Context) { - ctx.Data["Title"] = ctx.Tr("admin.hooks") - ctx.Data["Description"] = ctx.Tr("admin.hooks.desc") - - // Are we looking at default webhooks? var ws []*models.Webhook var err error + + // Are we looking at default webhooks? if strings.Contains(ctx.Link, "/admin/hooks") { + ctx.Data["Title"] = ctx.Tr("admin.hooks") + ctx.Data["Description"] = ctx.Tr("admin.hooks.desc") ctx.Data["PageIsAdminHooks"] = true ctx.Data["BaseLink"] = setting.AppSubURL + "/admin/hooks" ws, err = models.GetDefaultWebhooks() } else { + ctx.Data["Title"] = ctx.Tr("admin.systemhooks") + ctx.Data["Description"] = ctx.Tr("admin.systemhooks.desc") ctx.Data["PageIsAdminSystemHooks"] = true ctx.Data["BaseLink"] = setting.AppSubURL + "/admin/system-hooks" ws, err = models.GetSystemWebhooks() diff --git a/routers/repo/webhook.go b/routers/repo/webhook.go index ce3ba537d5241..f2e5760b0f0f0 100644 --- a/routers/repo/webhook.go +++ b/routers/repo/webhook.go @@ -558,11 +558,6 @@ func checkWebhook(ctx *context.Context) (*orgRepoCtx, *models.Webhook) { } ctx.Data["BaseLink"] = orCtx.Link - // Used to inform the admin template the difference between default and system webhooks - if orCtx.IsSystemWebhook { - ctx.Data["IsSystemWebhook"] = true - } - var w *models.Webhook // Why different methods if only the ID matters? if orCtx.RepoID > 0 { diff --git a/templates/admin/navbar.tmpl b/templates/admin/navbar.tmpl index caa8c1f323795..b9f86d88e12a4 100644 --- a/templates/admin/navbar.tmpl +++ b/templates/admin/navbar.tmpl @@ -14,6 +14,9 @@ {{.i18n.Tr "admin.hooks"}} + + {{.i18n.Tr "admin.systemhooks"}} + {{.i18n.Tr "admin.authentication"}} From af76998291ca7d7c289abaf8f45bde9c94681664 Mon Sep 17 00:00:00 2001 From: James Lakin Date: Sun, 1 Mar 2020 12:19:09 +0000 Subject: [PATCH 10/15] Use router params to differentiate admin hook pages --- routers/admin/hooks.go | 4 +--- routers/repo/webhook.go | 2 +- routers/routes/routes.go | 2 +- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/routers/admin/hooks.go b/routers/admin/hooks.go index 535bb75132519..c764fd9b7650f 100644 --- a/routers/admin/hooks.go +++ b/routers/admin/hooks.go @@ -5,8 +5,6 @@ package admin import ( - "strings" - "code.gitea.io/gitea/models" "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/context" @@ -24,7 +22,7 @@ func DefaultAndSystemWebhooks(ctx *context.Context) { var err error // Are we looking at default webhooks? - if strings.Contains(ctx.Link, "/admin/hooks") { + if ctx.Params(":configType") == "hooks" { ctx.Data["Title"] = ctx.Tr("admin.hooks") ctx.Data["Description"] = ctx.Tr("admin.hooks.desc") ctx.Data["PageIsAdminHooks"] = true diff --git a/routers/repo/webhook.go b/routers/repo/webhook.go index f2e5760b0f0f0..bc1e921d73607 100644 --- a/routers/repo/webhook.go +++ b/routers/repo/webhook.go @@ -77,7 +77,7 @@ func getOrgRepoCtx(ctx *context.Context) (*orgRepoCtx, error) { if ctx.User.IsAdmin { // Are we looking at default webhooks? - if strings.Contains(ctx.Link, "/admin/hooks") { + if ctx.Params(":configType") == "hooks" { return &orgRepoCtx{ IsAdmin: true, Link: path.Join(setting.AppSubURL, "/admin/hooks"), diff --git a/routers/routes/routes.go b/routers/routes/routes.go index 7123e092f1465..47b510968a00f 100644 --- a/routers/routes/routes.go +++ b/routers/routes/routes.go @@ -453,7 +453,7 @@ func RegisterRoutes(m *macaron.Macaron) { m.Post("/delete", admin.DeleteRepo) }) - m.Group("/^:type(hooks|system-hooks)$", func() { + m.Group("/^:configType(hooks|system-hooks)$", func() { m.Get("", admin.DefaultAndSystemWebhooks) m.Post("/delete", admin.DeleteDefaultWebhook) m.Get("/:type/new", repo.WebhooksNew) From 1fa71fa3cf12035fd1bf1834f61a272b4f5687ff Mon Sep 17 00:00:00 2001 From: James Lakin Date: Sun, 1 Mar 2020 12:36:28 +0000 Subject: [PATCH 11/15] Fix deleting admin webhooks and rename method --- models/webhook.go | 6 +++--- routers/admin/hooks.go | 23 +++++++++++++++-------- routers/routes/routes.go | 4 ++-- 3 files changed, 20 insertions(+), 13 deletions(-) diff --git a/models/webhook.go b/models/webhook.go index f5a823d09b0d7..89041287b5d52 100644 --- a/models/webhook.go +++ b/models/webhook.go @@ -412,8 +412,8 @@ func DeleteWebhookByOrgID(orgID, id int64) error { }) } -// DeleteDefaultWebhook deletes an admin-default webhook by given ID. -func DeleteDefaultWebhook(id int64) error { +// DeleteDefaultSystemWebhook deletes an admin-configured default or system webhook (where Org and Repo ID both 0) +func DeleteDefaultSystemWebhook(id int64) error { sess := x.NewSession() defer sess.Close() if err := sess.Begin(); err != nil { @@ -421,7 +421,7 @@ func DeleteDefaultWebhook(id int64) error { } count, err := sess. - Where("repo_id=? AND org_id=? AND is_system_webhook=?", 0, 0, false). + Where("repo_id=? AND org_id=?", 0, 0). Delete(&Webhook{ID: id}) if err != nil { return err diff --git a/routers/admin/hooks.go b/routers/admin/hooks.go index c764fd9b7650f..4697c4d933f5a 100644 --- a/routers/admin/hooks.go +++ b/routers/admin/hooks.go @@ -16,8 +16,8 @@ const ( tplAdminHooks base.TplName = "admin/hooks" ) -// DefaultAndSystemWebhooks renders both admin default and system webhook list pages -func DefaultAndSystemWebhooks(ctx *context.Context) { +// DefaultOrSystemWebhooks renders both admin default and system webhook list pages +func DefaultOrSystemWebhooks(ctx *context.Context) { var ws []*models.Webhook var err error @@ -45,15 +45,22 @@ func DefaultAndSystemWebhooks(ctx *context.Context) { ctx.HTML(200, tplAdminHooks) } -// DeleteDefaultWebhook response for delete admin-default webhook -func DeleteDefaultWebhook(ctx *context.Context) { - if err := models.DeleteDefaultWebhook(ctx.QueryInt64("id")); err != nil { +// DeleteDefaultOrSystemWebhook handler to delete an admin-defined system or default webhook +func DeleteDefaultOrSystemWebhook(ctx *context.Context) { + if err := models.DeleteDefaultSystemWebhook(ctx.QueryInt64("id")); err != nil { ctx.Flash.Error("DeleteDefaultWebhook: " + err.Error()) } else { ctx.Flash.Success(ctx.Tr("repo.settings.webhook_deletion_success")) } - ctx.JSON(200, map[string]interface{}{ - "redirect": setting.AppSubURL + "/admin/hooks", - }) + // Are we looking at default webhooks? + if ctx.Params(":configType") == "hooks" { + ctx.JSON(200, map[string]interface{}{ + "redirect": setting.AppSubURL + "/admin/hooks", + }) + } else { + ctx.JSON(200, map[string]interface{}{ + "redirect": setting.AppSubURL + "/admin/system-hooks", + }) + } } diff --git a/routers/routes/routes.go b/routers/routes/routes.go index 47b510968a00f..401eca3d03ac1 100644 --- a/routers/routes/routes.go +++ b/routers/routes/routes.go @@ -454,8 +454,8 @@ func RegisterRoutes(m *macaron.Macaron) { }) m.Group("/^:configType(hooks|system-hooks)$", func() { - m.Get("", admin.DefaultAndSystemWebhooks) - m.Post("/delete", admin.DeleteDefaultWebhook) + m.Get("", admin.DefaultOrSystemWebhooks) + m.Post("/delete", admin.DeleteDefaultOrSystemWebhook) m.Get("/:type/new", repo.WebhooksNew) m.Post("/gitea/new", bindIgnErr(auth.NewWebhookForm{}), repo.WebHooksNewPost) m.Post("/gogs/new", bindIgnErr(auth.NewGogshookForm{}), repo.GogsHooksNewPost) From cadb48248074375cede0d6a82c2d21930344b781 Mon Sep 17 00:00:00 2001 From: James Lakin Date: Sun, 1 Mar 2020 12:36:49 +0000 Subject: [PATCH 12/15] Add clarity to webhook docs --- docs/content/doc/features/webhooks.en-us.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/content/doc/features/webhooks.en-us.md b/docs/content/doc/features/webhooks.en-us.md index 1a0a180e7a427..ec50c013f5060 100644 --- a/docs/content/doc/features/webhooks.en-us.md +++ b/docs/content/doc/features/webhooks.en-us.md @@ -15,24 +15,24 @@ menu: # Webhooks -Gitea supports web hooks for repository events. This can be found in the settings -page `/:username/:reponame/settings/hooks`. All event pushes are POST requests. -The methods currently supported are: +Gitea supports web hooks for repository events. This can be configured in the settings +page `/:username/:reponame/settings/hooks` by a repository admin. Webhooks can also be configured on a per-organization and whole system basis. +All event pushes are POST requests. The methods currently supported are: -- Gitea +- Gitea (can also be a GET request) - Gogs - Slack - Discord - Dingtalk - Telegram - Microsoft Teams +- Feishu ### Event information The following is an example of event information that will be sent by Gitea to a Payload URL: - ``` X-GitHub-Delivery: f6266f16-1bf3-46a5-9ea4-602e06ead473 X-GitHub-Event: push From a381e422975425289390244c2e689de963a534a9 Mon Sep 17 00:00:00 2001 From: James Lakin Date: Mon, 2 Mar 2020 09:52:32 +0000 Subject: [PATCH 13/15] Revert "Remove old unused admin nav template" This reverts commit 191a20a7389fe5f6256b0ad6aafd04b9b0e295c5. --- templates/admin/nav.tmpl | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 templates/admin/nav.tmpl diff --git a/templates/admin/nav.tmpl b/templates/admin/nav.tmpl new file mode 100644 index 0000000000000..d95a0d7ecfb49 --- /dev/null +++ b/templates/admin/nav.tmpl @@ -0,0 +1,16 @@ + From 85ede4d25dd2eb49285cf82b12c6de06ee623b67 Mon Sep 17 00:00:00 2001 From: James Lakin Date: Fri, 6 Mar 2020 08:06:59 +0000 Subject: [PATCH 14/15] Rename WebHooksNewPost to GiteaHooksNewPost for clarity --- routers/repo/webhook.go | 4 ++-- routers/routes/routes.go | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/routers/repo/webhook.go b/routers/repo/webhook.go index bc1e921d73607..62838c90064e9 100644 --- a/routers/repo/webhook.go +++ b/routers/repo/webhook.go @@ -165,8 +165,8 @@ func ParseHookEvent(form auth.WebhookForm) *models.HookEvent { } } -// WebHooksNewPost response for creating Gitea webhook -func WebHooksNewPost(ctx *context.Context, form auth.NewWebhookForm) { +// GiteaHooksNewPost response for creating Gitea webhook +func GiteaHooksNewPost(ctx *context.Context, form auth.NewWebhookForm) { ctx.Data["Title"] = ctx.Tr("repo.settings.add_webhook") ctx.Data["PageIsSettingsHooks"] = true ctx.Data["PageIsSettingsHooksNew"] = true diff --git a/routers/routes/routes.go b/routers/routes/routes.go index 401eca3d03ac1..45a6d0859d39c 100644 --- a/routers/routes/routes.go +++ b/routers/routes/routes.go @@ -457,7 +457,7 @@ func RegisterRoutes(m *macaron.Macaron) { m.Get("", admin.DefaultOrSystemWebhooks) m.Post("/delete", admin.DeleteDefaultOrSystemWebhook) m.Get("/:type/new", repo.WebhooksNew) - m.Post("/gitea/new", bindIgnErr(auth.NewWebhookForm{}), repo.WebHooksNewPost) + m.Post("/gitea/new", bindIgnErr(auth.NewWebhookForm{}), repo.GiteaHooksNewPost) m.Post("/gogs/new", bindIgnErr(auth.NewGogshookForm{}), repo.GogsHooksNewPost) m.Post("/slack/new", bindIgnErr(auth.NewSlackHookForm{}), repo.SlackHooksNewPost) m.Post("/discord/new", bindIgnErr(auth.NewDiscordHookForm{}), repo.DiscordHooksNewPost) @@ -564,7 +564,7 @@ func RegisterRoutes(m *macaron.Macaron) { m.Get("", org.Webhooks) m.Post("/delete", org.DeleteWebhook) m.Get("/:type/new", repo.WebhooksNew) - m.Post("/gitea/new", bindIgnErr(auth.NewWebhookForm{}), repo.WebHooksNewPost) + m.Post("/gitea/new", bindIgnErr(auth.NewWebhookForm{}), repo.GiteaHooksNewPost) m.Post("/gogs/new", bindIgnErr(auth.NewGogshookForm{}), repo.GogsHooksNewPost) m.Post("/slack/new", bindIgnErr(auth.NewSlackHookForm{}), repo.SlackHooksNewPost) m.Post("/discord/new", bindIgnErr(auth.NewDiscordHookForm{}), repo.DiscordHooksNewPost) @@ -630,7 +630,7 @@ func RegisterRoutes(m *macaron.Macaron) { m.Get("", repo.Webhooks) m.Post("/delete", repo.DeleteWebhook) m.Get("/:type/new", repo.WebhooksNew) - m.Post("/gitea/new", bindIgnErr(auth.NewWebhookForm{}), repo.WebHooksNewPost) + m.Post("/gitea/new", bindIgnErr(auth.NewWebhookForm{}), repo.GiteaHooksNewPost) m.Post("/gogs/new", bindIgnErr(auth.NewGogshookForm{}), repo.GogsHooksNewPost) m.Post("/slack/new", bindIgnErr(auth.NewSlackHookForm{}), repo.SlackHooksNewPost) m.Post("/discord/new", bindIgnErr(auth.NewDiscordHookForm{}), repo.DiscordHooksNewPost) From 0ae62a74252eaf7526faa81a38554fd6965ea5ac Mon Sep 17 00:00:00 2001 From: James Lakin Date: Fri, 6 Mar 2020 08:16:09 +0000 Subject: [PATCH 15/15] Reintroduce blank line lost during merge conflict --- models/migrations/v128.go | 1 + 1 file changed, 1 insertion(+) diff --git a/models/migrations/v128.go b/models/migrations/v128.go index 1b95b70a0e3a0..557282bf283e8 100644 --- a/models/migrations/v128.go +++ b/models/migrations/v128.go @@ -92,5 +92,6 @@ func fixMergeBase(x *xorm.Engine) error { x.ID(pr.ID).Cols("merge_base").Update(pr) } } + return nil }