System-wide webhooks (#10546)
* Create system webhook column (and migration) * Create system webhook DB methods Based on the default webhook ones * Modify router to handle system webhooks and default ones * Remove old unused admin nav template * Adjust orgRepoCtx to differentiate system and default webhook URLs * Assign IsSystemWebhook when creating webhooks * Correctly use booleans for IsSystemWebhook * Use system webhooks when preparing webhooks for payload * Add UI and locale changes * Use router params to differentiate admin hook pages * Fix deleting admin webhooks and rename method * Add clarity to webhook docs * Revert "Remove old unused admin nav template" This reverts commit 191a20a7389fe5f6256b0ad6aafd04b9b0e295c5. * Rename WebHooksNewPost to GiteaHooksNewPost for clarity * Reintroduce blank line lost during merge conflict Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com> Co-authored-by: Lauris BH <lauris@nix.lv>
This commit is contained in:
parent
b8551f8532
commit
a9f4489bbc
10 changed files with 232 additions and 122 deletions
|
@ -12,20 +12,32 @@ 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) {
|
||||
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")
|
||||
// DefaultOrSystemWebhooks renders both admin default and system webhook list pages
|
||||
func DefaultOrSystemWebhooks(ctx *context.Context) {
|
||||
var ws []*models.Webhook
|
||||
var err error
|
||||
|
||||
// Are we looking at default webhooks?
|
||||
if ctx.Params(":configType") == "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()
|
||||
}
|
||||
|
||||
ws, err := models.GetDefaultWebhooks()
|
||||
if err != nil {
|
||||
ctx.ServerError("GetWebhooksDefaults", err)
|
||||
ctx.ServerError("GetWebhooksAdmin", err)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -33,15 +45,22 @@ func DefaultWebhooks(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",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,10 +76,21 @@ func getOrgRepoCtx(ctx *context.Context) (*orgRepoCtx, error) {
|
|||
}
|
||||
|
||||
if ctx.User.IsAdmin {
|
||||
// Are we looking at default webhooks?
|
||||
if ctx.Params(":configType") == "hooks" {
|
||||
return &orgRepoCtx{
|
||||
IsAdmin: true,
|
||||
Link: path.Join(setting.AppSubURL, "/admin/hooks"),
|
||||
NewTemplate: tplAdminHookNew,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Must be system webhooks instead
|
||||
return &orgRepoCtx{
|
||||
IsAdmin: true,
|
||||
Link: path.Join(setting.AppSubURL, "/admin/hooks"),
|
||||
NewTemplate: tplAdminHookNew,
|
||||
IsAdmin: true,
|
||||
IsSystemWebhook: true,
|
||||
Link: path.Join(setting.AppSubURL, "/admin/system-hooks"),
|
||||
NewTemplate: tplAdminHookNew,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -159,8 +174,8 @@ func ParseHookEvent(form auth.WebhookForm) *models.HookEvent {
|
|||
}
|
||||
}
|
||||
|
||||
// WebHooksNewPost response for creating 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
|
||||
|
@ -185,15 +200,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)
|
||||
|
@ -238,14 +254,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)
|
||||
|
@ -287,14 +304,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)
|
||||
|
@ -327,14 +345,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)
|
||||
|
@ -376,14 +395,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)
|
||||
|
@ -416,14 +436,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)
|
||||
|
@ -473,14 +494,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)
|
||||
|
@ -513,14 +535,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)
|
||||
|
@ -549,6 +572,8 @@ func checkWebhook(ctx *context.Context) (*orgRepoCtx, *models.Webhook) {
|
|||
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"))
|
||||
}
|
||||
|
|
|
@ -458,11 +458,11 @@ func RegisterRoutes(m *macaron.Macaron) {
|
|||
m.Post("/delete", admin.DeleteRepo)
|
||||
})
|
||||
|
||||
m.Group("/hooks", func() {
|
||||
m.Get("", admin.DefaultWebhooks)
|
||||
m.Post("/delete", admin.DeleteDefaultWebhook)
|
||||
m.Group("/^:configType(hooks|system-hooks)$", func() {
|
||||
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)
|
||||
|
@ -569,7 +569,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)
|
||||
|
@ -635,7 +635,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)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue