[BRANDING] define the forgejo webhook type

templates/swagger/v1_json.tmpl updated with `make generate-swagger`

(cherry picked from commit 88899c492e)
(cherry picked from commit 7171bd9617)
(cherry picked from commit 1a742446c1)
(cherry picked from commit 132342ae8d)
(cherry picked from commit b47b815fbe)
(cherry picked from commit 2dbb52c8ec)
(cherry picked from commit c846de4322)
(cherry picked from commit c3d1ad7bbc)
This commit is contained in:
Earl Warren 2023-01-14 10:07:01 +01:00
parent 747f423125
commit 972c772c0e
No known key found for this signature in database
GPG key ID: 0579CB2928A78A00
13 changed files with 136 additions and 11 deletions

View file

@ -35,7 +35,7 @@ func loadWebhookFrom(rootCfg ConfigProvider) {
Webhook.DeliverTimeout = sec.Key("DELIVER_TIMEOUT").MustInt(5) Webhook.DeliverTimeout = sec.Key("DELIVER_TIMEOUT").MustInt(5)
Webhook.SkipTLSVerify = sec.Key("SKIP_TLS_VERIFY").MustBool() Webhook.SkipTLSVerify = sec.Key("SKIP_TLS_VERIFY").MustBool()
Webhook.AllowedHostList = sec.Key("ALLOWED_HOST_LIST").MustString("") Webhook.AllowedHostList = sec.Key("ALLOWED_HOST_LIST").MustString("")
Webhook.Types = []string{"gitea", "gogs", "slack", "discord", "dingtalk", "telegram", "msteams", "feishu", "matrix", "wechatwork", "packagist"} Webhook.Types = []string{"forgejo", "gitea", "gogs", "slack", "discord", "dingtalk", "telegram", "msteams", "feishu", "matrix", "wechatwork", "packagist"}
Webhook.PagingNum = sec.Key("PAGING_NUM").MustInt(10) Webhook.PagingNum = sec.Key("PAGING_NUM").MustInt(10)
Webhook.ProxyURL = sec.Key("PROXY_URL").MustString("") Webhook.ProxyURL = sec.Key("PROXY_URL").MustString("")
if Webhook.ProxyURL != "" { if Webhook.ProxyURL != "" {

View file

@ -40,7 +40,7 @@ type CreateHookOptionConfig map[string]string
// CreateHookOption options when create a hook // CreateHookOption options when create a hook
type CreateHookOption struct { type CreateHookOption struct {
// required: true // required: true
// enum: dingtalk,discord,gitea,gogs,msteams,slack,telegram,feishu,wechatwork,packagist // enum: forgejo,dingtalk,discord,gitea,gogs,msteams,slack,telegram,feishu,wechatwork,packagist
Type string `json:"type" binding:"Required"` Type string `json:"type" binding:"Required"`
// required: true // required: true
Config CreateHookOptionConfig `json:"config" binding:"Required"` Config CreateHookOptionConfig `json:"config" binding:"Required"`

View file

@ -71,6 +71,7 @@ type HookType = string
// Types of webhooks // Types of webhooks
const ( const (
FORGEJO HookType = "forgejo"
GITEA HookType = "gitea" GITEA HookType = "gitea"
GOGS HookType = "gogs" GOGS HookType = "gogs"
SLACK HookType = "slack" SLACK HookType = "slack"

View file

@ -308,6 +308,34 @@ func editWebhook(ctx *context.Context, params webhookParams) {
ctx.Redirect(fmt.Sprintf("%s/%d", orCtx.Link, w.ID)) ctx.Redirect(fmt.Sprintf("%s/%d", orCtx.Link, w.ID))
} }
// ForgejoHooksNewPost response for creating Forgejo webhook
func ForgejoHooksNewPost(ctx *context.Context) {
createWebhook(ctx, forgejoHookParams(ctx))
}
// ForgejoHooksEditPost response for editing Forgejo webhook
func ForgejoHooksEditPost(ctx *context.Context) {
editWebhook(ctx, forgejoHookParams(ctx))
}
func forgejoHookParams(ctx *context.Context) webhookParams {
form := web.GetForm(ctx).(*forms.NewWebhookForm)
contentType := webhook.ContentTypeJSON
if webhook.HookContentType(form.ContentType) == webhook.ContentTypeForm {
contentType = webhook.ContentTypeForm
}
return webhookParams{
Type: webhook_module.FORGEJO,
URL: form.PayloadURL,
ContentType: contentType,
Secret: form.Secret,
HTTPMethod: form.HTTPMethod,
WebhookForm: form.WebhookForm,
}
}
// GiteaHooksNewPost response for creating Gitea webhook // GiteaHooksNewPost response for creating Gitea webhook
func GiteaHooksNewPost(ctx *context.Context) { func GiteaHooksNewPost(ctx *context.Context) {
createWebhook(ctx, giteaHookParams(ctx)) createWebhook(ctx, giteaHookParams(ctx))

View file

@ -577,6 +577,7 @@ func RegisterRoutes(m *web.Route) {
m.Get("", repo.WebHooksEdit) m.Get("", repo.WebHooksEdit)
m.Post("/replay/{uuid}", repo.ReplayWebhook) m.Post("/replay/{uuid}", repo.ReplayWebhook)
}) })
m.Post("/forgejo/{id}", web.Bind(forms.NewWebhookForm{}), repo.ForgejoHooksEditPost)
m.Post("/gitea/{id}", web.Bind(forms.NewWebhookForm{}), repo.GiteaHooksEditPost) m.Post("/gitea/{id}", web.Bind(forms.NewWebhookForm{}), repo.GiteaHooksEditPost)
m.Post("/gogs/{id}", web.Bind(forms.NewGogshookForm{}), repo.GogsHooksEditPost) m.Post("/gogs/{id}", web.Bind(forms.NewGogshookForm{}), repo.GogsHooksEditPost)
m.Post("/slack/{id}", web.Bind(forms.NewSlackHookForm{}), repo.SlackHooksEditPost) m.Post("/slack/{id}", web.Bind(forms.NewSlackHookForm{}), repo.SlackHooksEditPost)
@ -592,6 +593,7 @@ func RegisterRoutes(m *web.Route) {
m.Group("/{configType:default-hooks|system-hooks}", func() { m.Group("/{configType:default-hooks|system-hooks}", func() {
m.Get("/{type}/new", repo.WebhooksNew) m.Get("/{type}/new", repo.WebhooksNew)
m.Post("/forgejo/new", web.Bind(forms.NewWebhookForm{}), repo.ForgejoHooksNewPost)
m.Post("/gitea/new", web.Bind(forms.NewWebhookForm{}), repo.GiteaHooksNewPost) m.Post("/gitea/new", web.Bind(forms.NewWebhookForm{}), repo.GiteaHooksNewPost)
m.Post("/gogs/new", web.Bind(forms.NewGogshookForm{}), repo.GogsHooksNewPost) m.Post("/gogs/new", web.Bind(forms.NewGogshookForm{}), repo.GogsHooksNewPost)
m.Post("/slack/new", web.Bind(forms.NewSlackHookForm{}), repo.SlackHooksNewPost) m.Post("/slack/new", web.Bind(forms.NewSlackHookForm{}), repo.SlackHooksNewPost)
@ -808,6 +810,7 @@ func RegisterRoutes(m *web.Route) {
m.Get("", org.Webhooks) m.Get("", org.Webhooks)
m.Post("/delete", org.DeleteWebhook) m.Post("/delete", org.DeleteWebhook)
m.Get("/{type}/new", repo.WebhooksNew) m.Get("/{type}/new", repo.WebhooksNew)
m.Post("/forgejo/new", web.Bind(forms.NewWebhookForm{}), repo.ForgejoHooksNewPost)
m.Post("/gitea/new", web.Bind(forms.NewWebhookForm{}), repo.GiteaHooksNewPost) m.Post("/gitea/new", web.Bind(forms.NewWebhookForm{}), repo.GiteaHooksNewPost)
m.Post("/gogs/new", web.Bind(forms.NewGogshookForm{}), repo.GogsHooksNewPost) m.Post("/gogs/new", web.Bind(forms.NewGogshookForm{}), repo.GogsHooksNewPost)
m.Post("/slack/new", web.Bind(forms.NewSlackHookForm{}), repo.SlackHooksNewPost) m.Post("/slack/new", web.Bind(forms.NewSlackHookForm{}), repo.SlackHooksNewPost)
@ -822,6 +825,7 @@ func RegisterRoutes(m *web.Route) {
m.Get("", repo.WebHooksEdit) m.Get("", repo.WebHooksEdit)
m.Post("/replay/{uuid}", repo.ReplayWebhook) m.Post("/replay/{uuid}", repo.ReplayWebhook)
}) })
m.Post("/forgejo/{id}", web.Bind(forms.NewWebhookForm{}), repo.ForgejoHooksEditPost)
m.Post("/gitea/{id}", web.Bind(forms.NewWebhookForm{}), repo.GiteaHooksEditPost) m.Post("/gitea/{id}", web.Bind(forms.NewWebhookForm{}), repo.GiteaHooksEditPost)
m.Post("/gogs/{id}", web.Bind(forms.NewGogshookForm{}), repo.GogsHooksEditPost) m.Post("/gogs/{id}", web.Bind(forms.NewGogshookForm{}), repo.GogsHooksEditPost)
m.Post("/slack/{id}", web.Bind(forms.NewSlackHookForm{}), repo.SlackHooksEditPost) m.Post("/slack/{id}", web.Bind(forms.NewSlackHookForm{}), repo.SlackHooksEditPost)
@ -1006,6 +1010,7 @@ func RegisterRoutes(m *web.Route) {
m.Get("", repo.Webhooks) m.Get("", repo.Webhooks)
m.Post("/delete", repo.DeleteWebhook) m.Post("/delete", repo.DeleteWebhook)
m.Get("/{type}/new", repo.WebhooksNew) m.Get("/{type}/new", repo.WebhooksNew)
m.Post("/forgejo/new", web.Bind(forms.NewWebhookForm{}), repo.ForgejoHooksNewPost)
m.Post("/gitea/new", web.Bind(forms.NewWebhookForm{}), repo.GiteaHooksNewPost) m.Post("/gitea/new", web.Bind(forms.NewWebhookForm{}), repo.GiteaHooksNewPost)
m.Post("/gogs/new", web.Bind(forms.NewGogshookForm{}), repo.GogsHooksNewPost) m.Post("/gogs/new", web.Bind(forms.NewGogshookForm{}), repo.GogsHooksNewPost)
m.Post("/slack/new", web.Bind(forms.NewSlackHookForm{}), repo.SlackHooksNewPost) m.Post("/slack/new", web.Bind(forms.NewSlackHookForm{}), repo.SlackHooksNewPost)
@ -1022,6 +1027,7 @@ func RegisterRoutes(m *web.Route) {
m.Post("/test", repo.TestWebhook) m.Post("/test", repo.TestWebhook)
m.Post("/replay/{uuid}", repo.ReplayWebhook) m.Post("/replay/{uuid}", repo.ReplayWebhook)
}) })
m.Post("/forgejo/{id}", web.Bind(forms.NewWebhookForm{}), repo.ForgejoHooksEditPost)
m.Post("/gitea/{id}", web.Bind(forms.NewWebhookForm{}), repo.GiteaHooksEditPost) m.Post("/gitea/{id}", web.Bind(forms.NewWebhookForm{}), repo.GiteaHooksEditPost)
m.Post("/gogs/{id}", web.Bind(forms.NewGogshookForm{}), repo.GogsHooksEditPost) m.Post("/gogs/{id}", web.Bind(forms.NewGogshookForm{}), repo.GogsHooksEditPost)
m.Post("/slack/{id}", web.Bind(forms.NewSlackHookForm{}), repo.SlackHooksEditPost) m.Post("/slack/{id}", web.Bind(forms.NewSlackHookForm{}), repo.SlackHooksEditPost)

View file

@ -69,7 +69,7 @@ var webhooks = map[webhook_module.HookType]*webhook{
// IsValidHookTaskType returns true if a webhook registered // IsValidHookTaskType returns true if a webhook registered
func IsValidHookTaskType(name string) bool { func IsValidHookTaskType(name string) bool {
if name == webhook_module.GITEA || name == webhook_module.GOGS { if name == webhook_module.FORGEJO || name == webhook_module.GITEA || name == webhook_module.GOGS {
return true return true
} }
_, ok := webhooks[name] _, ok := webhooks[name]
@ -172,7 +172,7 @@ func PrepareWebhook(ctx context.Context, w *webhook_model.Webhook, event webhook
// Avoid sending "0 new commits" to non-integration relevant webhooks (e.g. slack, discord, etc.). // Avoid sending "0 new commits" to non-integration relevant webhooks (e.g. slack, discord, etc.).
// Integration webhooks (e.g. drone) still receive the required data. // Integration webhooks (e.g. drone) still receive the required data.
if pushEvent, ok := p.(*api.PushPayload); ok && if pushEvent, ok := p.(*api.PushPayload); ok &&
w.Type != webhook_module.GITEA && w.Type != webhook_module.GOGS && w.Type != webhook_module.FORGEJO && w.Type != webhook_module.GITEA && w.Type != webhook_module.GOGS &&
len(pushEvent.Commits) == 0 { len(pushEvent.Commits) == 0 {
return nil return nil
} }

View file

@ -14,8 +14,10 @@
{{.locale.Tr "admin.defaulthooks.update_webhook"}} {{.locale.Tr "admin.defaulthooks.update_webhook"}}
{{end}} {{end}}
<div class="ui right"> <div class="ui right">
{{if eq .HookType "gitea"}} {{if eq .HookType "forgejo"}}
<img width="26" height="26" src="{{AssetUrlPrefix}}/img/gitea.svg"> <img width="26" height="26" src="{{AssetUrlPrefix}}/img/forgejo.svg">
{{else if eq .HookType "gitea"}}
<img width="26" height="26" src="{{AssetUrlPrefix}}/img/gitea-original.svg">
{{else if eq .HookType "gogs"}} {{else if eq .HookType "gogs"}}
<img width="26" height="26" src="{{AssetUrlPrefix}}/img/gogs.ico"> <img width="26" height="26" src="{{AssetUrlPrefix}}/img/gogs.ico">
{{else if eq .HookType "slack"}} {{else if eq .HookType "slack"}}
@ -40,6 +42,7 @@
</div> </div>
</h4> </h4>
<div class="ui attached segment"> <div class="ui attached segment">
{{template "repo/settings/webhook/forgejo" .}}
{{template "repo/settings/webhook/gitea" .}} {{template "repo/settings/webhook/gitea" .}}
{{template "repo/settings/webhook/gogs" .}} {{template "repo/settings/webhook/gogs" .}}
{{template "repo/settings/webhook/slack" .}} {{template "repo/settings/webhook/slack" .}}

View file

@ -9,8 +9,10 @@
<h4 class="ui top attached header"> <h4 class="ui top attached header">
{{if .PageIsSettingsHooksNew}}{{.locale.Tr "repo.settings.add_webhook"}}{{else}}{{.locale.Tr "repo.settings.update_webhook"}}{{end}} {{if .PageIsSettingsHooksNew}}{{.locale.Tr "repo.settings.add_webhook"}}{{else}}{{.locale.Tr "repo.settings.update_webhook"}}{{end}}
<div class="ui right"> <div class="ui right">
{{if eq .HookType "gitea"}} {{if eq .HookType "forgejo"}}
<img width="26" height="26" src="{{AssetUrlPrefix}}/img/gitea.svg"> <img width="26" height="26" src="{{AssetUrlPrefix}}/img/forgejo.svg">
{{else if eq .HookType "gitea"}}
<img width="26" height="26" src="{{AssetUrlPrefix}}/img/gitea-original.svg">
{{else if eq .HookType "gogs"}} {{else if eq .HookType "gogs"}}
<img width="26" height="26" src="{{AssetUrlPrefix}}/img/gogs.ico"> <img width="26" height="26" src="{{AssetUrlPrefix}}/img/gogs.ico">
{{else if eq .HookType "slack"}} {{else if eq .HookType "slack"}}

View file

@ -4,8 +4,11 @@
<div class="ui floating1 jump dropdown"> <div class="ui floating1 jump dropdown">
<div class="ui primary tiny button">{{.locale.Tr "repo.settings.add_webhook"}}</div> <div class="ui primary tiny button">{{.locale.Tr "repo.settings.add_webhook"}}</div>
<div class="menu"> <div class="menu">
<a class="item" href="{{.BaseLinkNew}}/forgejo/new">
<img width="20" height="20" src="{{AssetUrlPrefix}}/img/forgejo.svg">{{.locale.Tr "repo.settings.web_hook_name_forgejo"}}
</a>
<a class="item" href="{{.BaseLinkNew}}/gitea/new"> <a class="item" href="{{.BaseLinkNew}}/gitea/new">
<img width="20" height="20" src="{{AssetUrlPrefix}}/img/gitea.svg">{{.locale.Tr "repo.settings.web_hook_name_gitea"}} <img width="20" height="20" src="{{AssetUrlPrefix}}/img/gitea-original.svg">{{.locale.Tr "repo.settings.web_hook_name_gitea"}}
</a> </a>
<a class="item" href="{{.BaseLinkNew}}/gogs/new"> <a class="item" href="{{.BaseLinkNew}}/gogs/new">
<img width="20" height="20" src="{{AssetUrlPrefix}}/img/gogs.ico">{{.locale.Tr "repo.settings.web_hook_name_gogs"}} <img width="20" height="20" src="{{AssetUrlPrefix}}/img/gogs.ico">{{.locale.Tr "repo.settings.web_hook_name_gogs"}}

View file

@ -0,0 +1,40 @@
{{if eq .HookType "forgejo"}}
<p>{{.locale.Tr "repo.settings.add_web_hook_desc" "https://docs.gitea.io/en-us/webhooks/" (.locale.Tr "repo.settings.web_hook_name_forgejo") | Str2html}}</p>
<form class="ui form" action="{{.BaseLink}}/forgejo/{{or .Webhook.ID "new"}}" method="post">
{{template "base/disable_form_autofill"}}
{{.CsrfTokenHtml}}
<div class="required field {{if .Err_PayloadURL}}error{{end}}">
<label for="payload_url">{{.locale.Tr "repo.settings.payload_url"}}</label>
<input id="payload_url" name="payload_url" type="url" value="{{.Webhook.URL}}" autofocus required>
</div>
<div class="field">
<label>{{.locale.Tr "repo.settings.http_method"}}</label>
<div class="ui selection dropdown">
<input type="hidden" id="http_method" name="http_method" value="{{if .Webhook.HTTPMethod}}{{.Webhook.HTTPMethod}}{{else}}POST{{end}}">
<div class="default text"></div>
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
<div class="menu">
<div class="item" data-value="POST">POST</div>
<div class="item" data-value="GET">GET</div>
</div>
</div>
</div>
<div class="field">
<label>{{.locale.Tr "repo.settings.content_type"}}</label>
<div class="ui selection dropdown">
<input type="hidden" id="content_type" name="content_type" value="{{if .Webhook.ContentType}}{{.Webhook.ContentType}}{{else}}1{{end}}">
<div class="default text"></div>
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
<div class="menu">
<div class="item" data-value="1">application/json</div>
<div class="item" data-value="2">application/x-www-form-urlencoded</div>
</div>
</div>
</div>
<div class="field {{if .Err_Secret}}error{{end}}">
<label for="secret">{{.locale.Tr "repo.settings.secret"}}</label>
<input id="secret" name="secret" type="password" value="{{.Webhook.Secret}}" autocomplete="off">
</div>
{{template "repo/settings/webhook/settings" .}}
</form>
{{end}}

View file

@ -7,8 +7,10 @@
<h4 class="ui top attached header"> <h4 class="ui top attached header">
{{if .PageIsSettingsHooksNew}}{{.locale.Tr "repo.settings.add_webhook"}}{{else}}{{.locale.Tr "repo.settings.update_webhook"}}{{end}} {{if .PageIsSettingsHooksNew}}{{.locale.Tr "repo.settings.add_webhook"}}{{else}}{{.locale.Tr "repo.settings.update_webhook"}}{{end}}
<div class="ui right"> <div class="ui right">
{{if eq .HookType "gitea"}} {{if eq .HookType "forgejo"}}
<img width="26" height="26" src="{{AssetUrlPrefix}}/img/gitea.svg"> <img width="26" height="26" src="{{AssetUrlPrefix}}/img/forgejo.svg">
{{else if eq .HookType "gitea"}}
<img width="26" height="26" src="{{AssetUrlPrefix}}/img/gitea-original.svg">
{{else if eq .HookType "gogs"}} {{else if eq .HookType "gogs"}}
<img width="26" height="26" src="{{AssetUrlPrefix}}/img/gogs.ico"> <img width="26" height="26" src="{{AssetUrlPrefix}}/img/gogs.ico">
{{else if eq .HookType "slack"}} {{else if eq .HookType "slack"}}
@ -33,6 +35,7 @@
</div> </div>
</h4> </h4>
<div class="ui attached segment"> <div class="ui attached segment">
{{template "repo/settings/webhook/forgejo" .}}
{{template "repo/settings/webhook/gitea" .}} {{template "repo/settings/webhook/gitea" .}}
{{template "repo/settings/webhook/gogs" .}} {{template "repo/settings/webhook/gogs" .}}
{{template "repo/settings/webhook/slack" .}} {{template "repo/settings/webhook/slack" .}}

View file

@ -15236,6 +15236,7 @@
"type": { "type": {
"type": "string", "type": "string",
"enum": [ "enum": [
"forgejo",
"dingtalk", "dingtalk",
"discord", "discord",
"gitea", "gitea",

View file

@ -173,3 +173,41 @@ func TestLinksLogin(t *testing.T) {
testLinksAsUser("user2", t) testLinksAsUser("user2", t)
} }
func TestRedirectsWebhooks(t *testing.T) {
defer tests.PrepareTestEnv(t)()
//
// A redirect means the route exists but not if it performs as intended.
//
for _, kind := range []string{"forgejo", "gitea"} {
{
redirects := map[string]string{
"/user2/repo1/settings/hooks/" + kind + "/new": "/user/login",
"/admin/system-hooks/" + kind + "/new": "/user/login",
"/admin/default-hooks/" + kind + "/new": "/user/login",
}
for link, redirectLink := range redirects {
req := NewRequest(t, "GET", link)
resp := MakeRequest(t, req, http.StatusSeeOther)
assert.EqualValues(t, path.Join(setting.AppSubURL, redirectLink), test.RedirectURL(resp))
}
}
{
redirects := map[string]string{
"/user2/repo1/settings/hooks/" + kind + "/new": "/",
"/admin/system-hooks/" + kind + "/new": "/",
"/admin/default-hooks/" + kind + "/new": "/",
"/user2/repo1/settings/hooks/" + kind + "/1": "/",
"/admin/hooks/" + kind + "/1": "/",
}
for link, redirectLink := range redirects {
req := NewRequest(t, "POST", link)
resp := MakeRequest(t, req, http.StatusSeeOther)
assert.EqualValues(t, path.Join(setting.AppSubURL, redirectLink), test.RedirectURL(resp))
}
}
}
}