loading up the forgejo repo on tangled to test page performance
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge pull request '[REFACTOR] webhook endpoint logic cleanup' (#2847) from oliverpool/forgejo:webhook_4_cleanup_endpoints into forgejo

Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/2847
Reviewed-by: Earl Warren <earl-warren@noreply.codeberg.org>

+120 -150
-2
modules/setting/webhook.go
··· 15 15 DeliverTimeout int 16 16 SkipTLSVerify bool 17 17 AllowedHostList string 18 - Types []string 19 18 PagingNum int 20 19 ProxyURL string 21 20 ProxyURLFixed *url.URL ··· 35 34 Webhook.DeliverTimeout = sec.Key("DELIVER_TIMEOUT").MustInt(5) 36 35 Webhook.SkipTLSVerify = sec.Key("SKIP_TLS_VERIFY").MustBool() 37 36 Webhook.AllowedHostList = sec.Key("ALLOWED_HOST_LIST").MustString("") 38 - Webhook.Types = []string{"forgejo", "gitea", "gogs", "slack", "discord", "dingtalk", "telegram", "msteams", "feishu", "matrix", "wechatwork", "packagist"} 39 37 Webhook.PagingNum = sec.Key("PAGING_NUM").MustInt(10) 40 38 Webhook.ProxyURL = sec.Key("PROXY_URL").MustString("") 41 39 if Webhook.ProxyURL != "" {
+71 -103
routers/web/repo/setting/webhook.go
··· 10 10 "net/http" 11 11 "net/url" 12 12 "path" 13 - "strings" 14 13 15 14 "code.gitea.io/gitea/models/db" 16 15 "code.gitea.io/gitea/models/perm" ··· 22 21 "code.gitea.io/gitea/modules/json" 23 22 "code.gitea.io/gitea/modules/setting" 24 23 api "code.gitea.io/gitea/modules/structs" 25 - "code.gitea.io/gitea/modules/util" 26 24 "code.gitea.io/gitea/modules/web/middleware" 27 25 webhook_module "code.gitea.io/gitea/modules/webhook" 28 26 "code.gitea.io/gitea/services/context" ··· 41 39 tplAdminHookNew base.TplName = "admin/hook_new" 42 40 ) 43 41 44 - // Webhooks render web hooks list page 45 - func Webhooks(ctx *context.Context) { 42 + // WebhookList render web hooks list page 43 + func WebhookList(ctx *context.Context) { 46 44 ctx.Data["Title"] = ctx.Tr("repo.settings.hooks") 47 45 ctx.Data["PageIsSettingsHooks"] = true 48 46 ctx.Data["BaseLink"] = ctx.Repo.RepoLink + "/settings/hooks" ··· 111 109 return nil, errors.New("unable to set OwnerRepo context") 112 110 } 113 111 114 - func checkHookType(ctx *context.Context) string { 115 - hookType := strings.ToLower(ctx.Params(":type")) 116 - if !util.SliceContainsString(setting.Webhook.Types, hookType, true) { 117 - ctx.NotFound("checkHookType", nil) 118 - return "" 119 - } 120 - return hookType 121 - } 122 - 123 - // WebhooksNew render creating webhook page 124 - func WebhooksNew(ctx *context.Context) { 112 + // WebhookNew render creating webhook page 113 + func WebhookNew(ctx *context.Context) { 125 114 ctx.Data["Title"] = ctx.Tr("repo.settings.add_webhook") 126 115 ctx.Data["Webhook"] = webhook.Webhook{HookEvent: &webhook_module.HookEvent{}} 127 116 ··· 142 131 ctx.Data["PageIsSettingsHooksNew"] = true 143 132 } 144 133 145 - hookType := checkHookType(ctx) 146 - ctx.Data["HookType"] = hookType 147 - if ctx.Written() { 134 + hookType := ctx.Params(":type") 135 + if webhook_service.GetWebhookHandler(hookType) == nil { 136 + ctx.NotFound("GetWebhookHandler", nil) 148 137 return 149 138 } 150 - if hookType == "discord" { 151 - ctx.Data["DiscordHook"] = map[string]any{ 152 - "Username": "Gitea", 153 - } 154 - } 139 + ctx.Data["HookType"] = hookType 155 140 ctx.Data["BaseLink"] = orCtx.LinkNew 156 141 ctx.Data["BaseLinkNew"] = orCtx.LinkNew 157 142 ··· 191 176 } 192 177 } 193 178 194 - type webhookParams struct { 195 - // Type should be imported from webhook package (webhook.XXX) 196 - Type string 197 - 198 - URL string 199 - ContentType webhook.HookContentType 200 - Secret string 201 - HTTPMethod string 202 - WebhookForm forms.WebhookForm 203 - Meta any 204 - } 205 - 206 179 func WebhookCreate(ctx *context.Context) { 207 - typ := ctx.Params(":type") 208 - handler := webhook_service.GetWebhookHandler(typ) 180 + hookType := ctx.Params(":type") 181 + handler := webhook_service.GetWebhookHandler(hookType) 209 182 if handler == nil { 210 183 ctx.NotFound("GetWebhookHandler", nil) 211 184 return ··· 213 186 214 187 fields := handler.FormFields(func(form any) { 215 188 errs := binding.Bind(ctx.Req, form) 216 - middleware.Validate(errs, ctx.Data, form, ctx.Locale) // error will be checked later in ctx.HasError 217 - }) 218 - createWebhook(ctx, webhookParams{ 219 - Type: typ, 220 - URL: fields.URL, 221 - ContentType: fields.ContentType, 222 - Secret: fields.Secret, 223 - HTTPMethod: fields.HTTPMethod, 224 - WebhookForm: fields.WebhookForm, 225 - Meta: fields.Metadata, 189 + middleware.Validate(errs, ctx.Data, form, ctx.Locale) // error checked below in ctx.HasError 226 190 }) 227 - } 228 191 229 - func createWebhook(ctx *context.Context, params webhookParams) { 230 192 ctx.Data["Title"] = ctx.Tr("repo.settings.add_webhook") 231 193 ctx.Data["PageIsSettingsHooks"] = true 232 194 ctx.Data["PageIsSettingsHooksNew"] = true 233 195 ctx.Data["Webhook"] = webhook.Webhook{HookEvent: &webhook_module.HookEvent{}} 234 - ctx.Data["HookType"] = params.Type 196 + ctx.Data["HookType"] = hookType 235 197 236 198 orCtx, err := getOwnerRepoCtx(ctx) 237 199 if err != nil { ··· 242 204 ctx.Data["BaseLinkNew"] = orCtx.LinkNew 243 205 244 206 if ctx.HasError() { 207 + // pre-fill the form with the submitted data 208 + var w webhook.Webhook 209 + w.URL = fields.URL 210 + w.ContentType = fields.ContentType 211 + w.Secret = fields.Secret 212 + w.HookEvent = ParseHookEvent(fields.WebhookForm) 213 + w.IsActive = fields.WebhookForm.Active 214 + w.HTTPMethod = fields.HTTPMethod 215 + err := w.SetHeaderAuthorization(fields.WebhookForm.AuthorizationHeader) 216 + if err != nil { 217 + ctx.ServerError("SetHeaderAuthorization", err) 218 + return 219 + } 220 + ctx.Data["Webhook"] = w 221 + ctx.Data["HookMetadata"] = fields.Metadata 222 + 245 223 ctx.HTML(http.StatusUnprocessableEntity, orCtx.NewTemplate) 246 224 return 247 225 } 248 226 249 227 var meta []byte 250 - if params.Meta != nil { 251 - meta, err = json.Marshal(params.Meta) 228 + if fields.Metadata != nil { 229 + meta, err = json.Marshal(fields.Metadata) 252 230 if err != nil { 253 231 ctx.ServerError("Marshal", err) 254 232 return ··· 257 235 258 236 w := &webhook.Webhook{ 259 237 RepoID: orCtx.RepoID, 260 - URL: params.URL, 261 - HTTPMethod: params.HTTPMethod, 262 - ContentType: params.ContentType, 263 - Secret: params.Secret, 264 - HookEvent: ParseHookEvent(params.WebhookForm), 265 - IsActive: params.WebhookForm.Active, 266 - Type: params.Type, 238 + URL: fields.URL, 239 + HTTPMethod: fields.HTTPMethod, 240 + ContentType: fields.ContentType, 241 + Secret: fields.Secret, 242 + HookEvent: ParseHookEvent(fields.WebhookForm), 243 + IsActive: fields.WebhookForm.Active, 244 + Type: hookType, 267 245 Meta: string(meta), 268 246 OwnerID: orCtx.OwnerID, 269 247 IsSystemWebhook: orCtx.IsSystemWebhook, 270 248 } 271 - err = w.SetHeaderAuthorization(params.WebhookForm.AuthorizationHeader) 249 + err = w.SetHeaderAuthorization(fields.WebhookForm.AuthorizationHeader) 272 250 if err != nil { 273 251 ctx.ServerError("SetHeaderAuthorization", err) 274 252 return ··· 286 264 } 287 265 288 266 func WebhookUpdate(ctx *context.Context) { 289 - typ := ctx.Params(":type") 290 - handler := webhook_service.GetWebhookHandler(typ) 267 + ctx.Data["Title"] = ctx.Tr("repo.settings.update_webhook") 268 + ctx.Data["PageIsSettingsHooks"] = true 269 + ctx.Data["PageIsSettingsHooksEdit"] = true 270 + 271 + orCtx, w := checkWebhook(ctx) 272 + if ctx.Written() { 273 + return 274 + } 275 + ctx.Data["Webhook"] = w 276 + 277 + handler := webhook_service.GetWebhookHandler(w.Type) 291 278 if handler == nil { 292 279 ctx.NotFound("GetWebhookHandler", nil) 293 280 return ··· 295 282 296 283 fields := handler.FormFields(func(form any) { 297 284 errs := binding.Bind(ctx.Req, form) 298 - middleware.Validate(errs, ctx.Data, form, ctx.Locale) // error will be checked later in ctx.HasError 299 - }) 300 - editWebhook(ctx, webhookParams{ 301 - Type: typ, 302 - URL: fields.URL, 303 - ContentType: fields.ContentType, 304 - Secret: fields.Secret, 305 - HTTPMethod: fields.HTTPMethod, 306 - WebhookForm: fields.WebhookForm, 307 - Meta: fields.Metadata, 285 + middleware.Validate(errs, ctx.Data, form, ctx.Locale) // error checked below in ctx.HasError 308 286 }) 309 - } 310 287 311 - func editWebhook(ctx *context.Context, params webhookParams) { 312 - ctx.Data["Title"] = ctx.Tr("repo.settings.update_webhook") 313 - ctx.Data["PageIsSettingsHooks"] = true 314 - ctx.Data["PageIsSettingsHooksEdit"] = true 288 + // pre-fill the form with the submitted data 289 + w.URL = fields.URL 290 + w.ContentType = fields.ContentType 291 + w.Secret = fields.Secret 292 + w.HookEvent = ParseHookEvent(fields.WebhookForm) 293 + w.IsActive = fields.WebhookForm.Active 294 + w.HTTPMethod = fields.HTTPMethod 315 295 316 - orCtx, w := checkWebhook(ctx) 317 - if ctx.Written() { 296 + err := w.SetHeaderAuthorization(fields.WebhookForm.AuthorizationHeader) 297 + if err != nil { 298 + ctx.ServerError("SetHeaderAuthorization", err) 318 299 return 319 300 } 320 - ctx.Data["Webhook"] = w 321 301 322 302 if ctx.HasError() { 303 + ctx.Data["HookMetadata"] = fields.Metadata 323 304 ctx.HTML(http.StatusUnprocessableEntity, orCtx.NewTemplate) 324 305 return 325 306 } 326 307 327 308 var meta []byte 328 - var err error 329 - if params.Meta != nil { 330 - meta, err = json.Marshal(params.Meta) 309 + if fields.Metadata != nil { 310 + meta, err = json.Marshal(fields.Metadata) 331 311 if err != nil { 332 312 ctx.ServerError("Marshal", err) 333 313 return 334 314 } 335 315 } 336 316 337 - w.URL = params.URL 338 - w.ContentType = params.ContentType 339 - w.Secret = params.Secret 340 - w.HookEvent = ParseHookEvent(params.WebhookForm) 341 - w.IsActive = params.WebhookForm.Active 342 - w.HTTPMethod = params.HTTPMethod 343 317 w.Meta = string(meta) 344 318 345 - err = w.SetHeaderAuthorization(params.WebhookForm.AuthorizationHeader) 346 - if err != nil { 347 - ctx.ServerError("SetHeaderAuthorization", err) 348 - return 349 - } 350 - 351 319 if err := w.UpdateEvent(); err != nil { 352 320 ctx.ServerError("UpdateEvent", err) 353 321 return ··· 399 367 return orCtx, w 400 368 } 401 369 402 - // WebHooksEdit render editing web hook page 403 - func WebHooksEdit(ctx *context.Context) { 370 + // WebhookEdit render editing web hook page 371 + func WebhookEdit(ctx *context.Context) { 404 372 ctx.Data["Title"] = ctx.Tr("repo.settings.update_webhook") 405 373 ctx.Data["PageIsSettingsHooks"] = true 406 374 ctx.Data["PageIsSettingsHooksEdit"] = true ··· 414 382 ctx.HTML(http.StatusOK, orCtx.NewTemplate) 415 383 } 416 384 417 - // TestWebhook test if web hook is work fine 418 - func TestWebhook(ctx *context.Context) { 385 + // WebhookTest test if web hook is work fine 386 + func WebhookTest(ctx *context.Context) { 419 387 hookID := ctx.ParamsInt64(":id") 420 388 w, err := webhook.GetWebhookByRepoID(ctx, ctx.Repo.Repository.ID, hookID) 421 389 if err != nil { ··· 475 443 } 476 444 } 477 445 478 - // ReplayWebhook replays a webhook 479 - func ReplayWebhook(ctx *context.Context) { 446 + // WebhookReplay replays a webhook 447 + func WebhookReplay(ctx *context.Context) { 480 448 hookTaskUUID := ctx.Params(":uuid") 481 449 482 450 orCtx, w := checkWebhook(ctx) ··· 497 465 ctx.Redirect(fmt.Sprintf("%s/%d", orCtx.Link, w.ID)) 498 466 } 499 467 500 - // DeleteWebhook delete a webhook 501 - func DeleteWebhook(ctx *context.Context) { 468 + // WebhookDelete delete a webhook 469 + func WebhookDelete(ctx *context.Context) { 502 470 if err := webhook.DeleteWebhookByRepoID(ctx, ctx.Repo.Repository.ID, ctx.FormInt64("id")); err != nil { 503 471 ctx.Flash.Error("DeleteWebhookByRepoID: " + err.Error()) 504 472 } else {
+23 -28
routers/web/web.go
··· 400 400 } 401 401 } 402 402 403 - addWebhookAddRoutes := func() { 404 - m.Get("/{type}/new", repo_setting.WebhooksNew) 405 - m.Post("/{type}/new", repo_setting.WebhookCreate) 406 - } 407 - 408 - addWebhookEditRoutes := func() { 409 - m.Post("/{type}/{id:[0-9]+}", repo_setting.WebhookUpdate) 410 - } 411 - 412 403 addSettingsVariablesRoutes := func() { 413 404 m.Group("/variables", func() { 414 405 m.Get("", repo_setting.Variables) ··· 618 609 m.Group("/hooks", func() { 619 610 m.Get("", user_setting.Webhooks) 620 611 m.Post("/delete", user_setting.DeleteWebhook) 621 - addWebhookAddRoutes() 612 + m.Get("/{type}/new", repo_setting.WebhookNew) 613 + m.Post("/{type}/new", repo_setting.WebhookCreate) 622 614 m.Group("/{id}", func() { 623 - m.Get("", repo_setting.WebHooksEdit) 624 - m.Post("/replay/{uuid}", repo_setting.ReplayWebhook) 615 + m.Get("", repo_setting.WebhookEdit) 616 + m.Post("", repo_setting.WebhookUpdate) 617 + m.Post("/replay/{uuid}", repo_setting.WebhookReplay) 625 618 }) 626 - addWebhookEditRoutes() 627 619 }, webhooksEnabled) 628 620 629 621 m.Group("/blocked_users", func() { ··· 722 714 m.Get("", admin.DefaultOrSystemWebhooks) 723 715 m.Post("/delete", admin.DeleteDefaultOrSystemWebhook) 724 716 m.Group("/{id}", func() { 725 - m.Get("", repo_setting.WebHooksEdit) 726 - m.Post("/replay/{uuid}", repo_setting.ReplayWebhook) 717 + m.Get("", repo_setting.WebhookEdit) 718 + m.Post("", repo_setting.WebhookUpdate) 719 + m.Post("/replay/{uuid}", repo_setting.WebhookReplay) 727 720 }) 728 - addWebhookEditRoutes() 729 721 }, webhooksEnabled) 730 722 731 723 m.Group("/{configType:default-hooks|system-hooks}", func() { 732 - addWebhookAddRoutes() 724 + m.Get("/{type}/new", repo_setting.WebhookNew) 725 + m.Post("/{type}/new", repo_setting.WebhookCreate) 733 726 }) 734 727 735 728 m.Group("/auths", func() { ··· 887 880 m.Group("/hooks", func() { 888 881 m.Get("", org.Webhooks) 889 882 m.Post("/delete", org.DeleteWebhook) 890 - addWebhookAddRoutes() 883 + m.Get("/{type}/new", repo_setting.WebhookNew) 884 + m.Post("/{type}/new", repo_setting.WebhookCreate) 891 885 m.Group("/{id}", func() { 892 - m.Get("", repo_setting.WebHooksEdit) 893 - m.Post("/replay/{uuid}", repo_setting.ReplayWebhook) 886 + m.Get("", repo_setting.WebhookEdit) 887 + m.Post("", repo_setting.WebhookUpdate) 888 + m.Post("/replay/{uuid}", repo_setting.WebhookReplay) 894 889 }) 895 - addWebhookEditRoutes() 896 890 }, webhooksEnabled) 897 891 898 892 m.Group("/labels", func() { ··· 1059 1053 }, context.GitHookService()) 1060 1054 1061 1055 m.Group("/hooks", func() { 1062 - m.Get("", repo_setting.Webhooks) 1063 - m.Post("/delete", repo_setting.DeleteWebhook) 1064 - addWebhookAddRoutes() 1056 + m.Get("", repo_setting.WebhookList) 1057 + m.Post("/delete", repo_setting.WebhookDelete) 1058 + m.Get("/{type}/new", repo_setting.WebhookNew) 1059 + m.Post("/{type}/new", repo_setting.WebhookCreate) 1065 1060 m.Group("/{id}", func() { 1066 - m.Get("", repo_setting.WebHooksEdit) 1067 - m.Post("/test", repo_setting.TestWebhook) 1068 - m.Post("/replay/{uuid}", repo_setting.ReplayWebhook) 1061 + m.Get("", repo_setting.WebhookEdit) 1062 + m.Post("", repo_setting.WebhookUpdate) 1063 + m.Post("/test", repo_setting.WebhookTest) 1064 + m.Post("/replay/{uuid}", repo_setting.WebhookReplay) 1069 1065 }) 1070 - addWebhookEditRoutes() 1071 1066 }, webhooksEnabled) 1072 1067 1073 1068 m.Group("/keys", func() {
+1 -1
templates/repo/settings/webhook/dingtalk.tmpl
··· 1 1 {{if eq .HookType "dingtalk"}} 2 2 <p>{{ctx.Locale.Tr "repo.settings.add_web_hook_desc" "https://dingtalk.com" (ctx.Locale.Tr "repo.settings.web_hook_name_dingtalk")}}</p> 3 - <form class="ui form" action="{{.BaseLink}}/dingtalk/{{or .Webhook.ID "new"}}" method="post"> 3 + <form class="ui form" action="{{.BaseLink}}/{{or .Webhook.ID "dingtalk/new"}}" method="post"> 4 4 {{.CsrfTokenHtml}} 5 5 <div class="required field {{if .Err_PayloadURL}}error{{end}}"> 6 6 <label for="payload_url">{{ctx.Locale.Tr "repo.settings.payload_url"}}</label>
+1 -1
templates/repo/settings/webhook/discord.tmpl
··· 1 1 {{if eq .HookType "discord"}} 2 2 <p>{{ctx.Locale.Tr "repo.settings.add_web_hook_desc" "https://discord.com" (ctx.Locale.Tr "repo.settings.web_hook_name_discord")}}</p> 3 - <form class="ui form" action="{{.BaseLink}}/discord/{{or .Webhook.ID "new"}}" method="post"> 3 + <form class="ui form" action="{{.BaseLink}}/{{or .Webhook.ID "discord/new"}}" method="post"> 4 4 {{.CsrfTokenHtml}} 5 5 <div class="required field {{if .Err_PayloadURL}}error{{end}}"> 6 6 <label for="payload_url">{{ctx.Locale.Tr "repo.settings.payload_url"}}</label>
+1 -1
templates/repo/settings/webhook/feishu.tmpl
··· 1 1 {{if eq .HookType "feishu"}} 2 2 <p>{{ctx.Locale.Tr "repo.settings.add_web_hook_desc" "https://feishu.cn" (ctx.Locale.Tr "repo.settings.web_hook_name_feishu")}}</p> 3 3 <p>{{ctx.Locale.Tr "repo.settings.add_web_hook_desc" "https://larksuite.com" (ctx.Locale.Tr "repo.settings.web_hook_name_larksuite")}}</p> 4 - <form class="ui form" action="{{.BaseLink}}/feishu/{{or .Webhook.ID "new"}}" method="post"> 4 + <form class="ui form" action="{{.BaseLink}}/{{or .Webhook.ID "feishu/new"}}" method="post"> 5 5 {{.CsrfTokenHtml}} 6 6 <div class="required field {{if .Err_PayloadURL}}error{{end}}"> 7 7 <label for="payload_url">{{ctx.Locale.Tr "repo.settings.payload_url"}}</label>
+1 -1
templates/repo/settings/webhook/forgejo.tmpl
··· 1 1 {{if eq .HookType "forgejo"}} 2 2 <p>{{ctx.Locale.Tr "repo.settings.add_web_hook_desc" "https://forgejo.org/docs/latest/user/webhooks/" (ctx.Locale.Tr "repo.settings.web_hook_name_forgejo")}}</p> 3 - <form class="ui form" action="{{.BaseLink}}/forgejo/{{or .Webhook.ID "new"}}" method="post"> 3 + <form class="ui form" action="{{.BaseLink}}/{{or .Webhook.ID "forgejo/new"}}" method="post"> 4 4 {{template "base/disable_form_autofill"}} 5 5 {{.CsrfTokenHtml}} 6 6 <div class="required field {{if .Err_PayloadURL}}error{{end}}">
+1 -1
templates/repo/settings/webhook/gitea.tmpl
··· 1 1 {{if eq .HookType "gitea"}} 2 2 <p>{{ctx.Locale.Tr "repo.settings.add_web_hook_desc" "https://forgejo.org/docs/latest/user/webhooks/" (ctx.Locale.Tr "repo.settings.web_hook_name_gitea")}}</p> 3 - <form class="ui form" action="{{.BaseLink}}/gitea/{{or .Webhook.ID "new"}}" method="post"> 3 + <form class="ui form" action="{{.BaseLink}}/{{or .Webhook.ID "gitea/new"}}" method="post"> 4 4 {{template "base/disable_form_autofill"}} 5 5 {{.CsrfTokenHtml}} 6 6 <div class="required field {{if .Err_PayloadURL}}error{{end}}">
+1 -1
templates/repo/settings/webhook/gogs.tmpl
··· 1 1 {{if eq .HookType "gogs"}} 2 2 <p>{{ctx.Locale.Tr "repo.settings.add_web_hook_desc" "https://forgejo.org/docs/latest/user/webhooks/" (ctx.Locale.Tr "repo.settings.web_hook_name_gogs")}}</p> 3 - <form class="ui form" action="{{.BaseLink}}/gogs/{{or .Webhook.ID "new"}}" method="post"> 3 + <form class="ui form" action="{{.BaseLink}}/{{or .Webhook.ID "gogs/new"}}" method="post"> 4 4 {{template "base/disable_form_autofill"}} 5 5 {{.CsrfTokenHtml}} 6 6 <div class="required field {{if .Err_PayloadURL}}error{{end}}">
+1 -1
templates/repo/settings/webhook/matrix.tmpl
··· 1 1 {{if eq .HookType "matrix"}} 2 2 <p>{{ctx.Locale.Tr "repo.settings.add_web_hook_desc" "https://matrix.org/" (ctx.Locale.Tr "repo.settings.web_hook_name_matrix")}}</p> 3 - <form class="ui form" action="{{.BaseLink}}/matrix/{{or .Webhook.ID "new"}}" method="post"> 3 + <form class="ui form" action="{{.BaseLink}}/{{or .Webhook.ID "matrix/new"}}" method="post"> 4 4 {{.CsrfTokenHtml}} 5 5 <div class="required field {{if .Err_HomeserverURL}}error{{end}}"> 6 6 <label for="homeserver_url">{{ctx.Locale.Tr "repo.settings.matrix.homeserver_url"}}</label>
+1 -1
templates/repo/settings/webhook/msteams.tmpl
··· 1 1 {{if eq .HookType "msteams"}} 2 2 <p>{{ctx.Locale.Tr "repo.settings.add_web_hook_desc" "https://teams.microsoft.com" (ctx.Locale.Tr "repo.settings.web_hook_name_msteams")}}</p> 3 - <form class="ui form" action="{{.BaseLink}}/msteams/{{or .Webhook.ID "new"}}" method="post"> 3 + <form class="ui form" action="{{.BaseLink}}/{{or .Webhook.ID "msteams/new"}}" method="post"> 4 4 {{.CsrfTokenHtml}} 5 5 <div class="required field {{if .Err_PayloadURL}}error{{end}}"> 6 6 <label for="payload_url">{{ctx.Locale.Tr "repo.settings.payload_url"}}</label>
+1 -1
templates/repo/settings/webhook/packagist.tmpl
··· 1 1 {{if eq .HookType "packagist"}} 2 2 <p>{{ctx.Locale.Tr "repo.settings.add_web_hook_desc" "https://packagist.org" (ctx.Locale.Tr "repo.settings.web_hook_name_packagist")}}</p> 3 - <form class="ui form" action="{{.BaseLink}}/packagist/{{or .Webhook.ID "new"}}" method="post"> 3 + <form class="ui form" action="{{.BaseLink}}/{{or .Webhook.ID "packagist/new"}}" method="post"> 4 4 {{.CsrfTokenHtml}} 5 5 <div class="required field {{if .Err_Username}}error{{end}}"> 6 6 <label for="username">{{ctx.Locale.Tr "repo.settings.packagist_username"}}</label>
+1 -1
templates/repo/settings/webhook/settings.tmpl
··· 259 259 </div> 260 260 261 261 <!-- Authorization Header --> 262 - <div class="field{{if eq .HookType "matrix"}} required{{end}}"> 262 + <div class="field{{if eq .HookType "matrix"}} required{{end}} {{if .Err_AuthorizationHeader}}error{{end}}"> 263 263 <label for="authorization_header">{{ctx.Locale.Tr "repo.settings.authorization_header"}}</label> 264 264 <input id="authorization_header" name="authorization_header" type="text" value="{{.Webhook.HeaderAuthorization}}"{{if eq .HookType "matrix"}} placeholder="Bearer $access_token" required{{end}}> 265 265 {{if ne .HookType "matrix"}}{{/* Matrix doesn't make the authorization optional but it is implied by the help string, should be changed.*/}}
+1 -1
templates/repo/settings/webhook/slack.tmpl
··· 1 1 {{if eq .HookType "slack"}} 2 2 <p>{{ctx.Locale.Tr "repo.settings.add_web_hook_desc" "https://slack.com" (ctx.Locale.Tr "repo.settings.web_hook_name_slack")}}</p> 3 - <form class="ui form" action="{{.BaseLink}}/slack/{{or .Webhook.ID "new"}}" method="post"> 3 + <form class="ui form" action="{{.BaseLink}}/{{or .Webhook.ID "slack/new"}}" method="post"> 4 4 {{.CsrfTokenHtml}} 5 5 <div class="required field {{if .Err_PayloadURL}}error{{end}}"> 6 6 <label for="payload_url">{{ctx.Locale.Tr "repo.settings.payload_url"}}</label>
+1 -1
templates/repo/settings/webhook/telegram.tmpl
··· 1 1 {{if eq .HookType "telegram"}} 2 2 <p>{{ctx.Locale.Tr "repo.settings.add_web_hook_desc" "https://core.telegram.org/bots" (ctx.Locale.Tr "repo.settings.web_hook_name_telegram")}}</p> 3 - <form class="ui form" action="{{.BaseLink}}/telegram/{{or .Webhook.ID "new"}}" method="post"> 3 + <form class="ui form" action="{{.BaseLink}}/{{or .Webhook.ID "telegram/new"}}" method="post"> 4 4 {{.CsrfTokenHtml}} 5 5 <div class="required field {{if .Err_BotToken}}error{{end}}"> 6 6 <label for="bot_token">{{ctx.Locale.Tr "repo.settings.bot_token"}}</label>
+1 -1
templates/repo/settings/webhook/wechatwork.tmpl
··· 1 1 {{if eq .HookType "wechatwork"}} 2 2 <p>{{ctx.Locale.Tr "repo.settings.add_web_hook_desc" "https://work.weixin.qq.com" (ctx.Locale.Tr "repo.settings.web_hook_name_wechatwork")}}</p> 3 - <form class="ui form" action="{{.BaseLink}}/wechatwork/{{or .Webhook.ID "new"}}" method="post"> 3 + <form class="ui form" action="{{.BaseLink}}/{{or .Webhook.ID "wechatwork/new"}}" method="post"> 4 4 {{.CsrfTokenHtml}} 5 5 <div class="required field {{if .Err_PayloadURL}}error{{end}}"> 6 6 <label for="payload_url">{{ctx.Locale.Tr "repo.settings.payload_url"}}</label>
+11 -2
tests/integration/repo_webhook_test.go
··· 52 52 htmlDoc := NewHTMLParser(t, resp.Body) 53 53 assert.Equal(t, webhooksLen, htmlDoc.Find(`a[href^="`+baseurl+`/"][href$="/new"]`).Length(), "not all webhooks are listed in the 'new' dropdown on failure") 54 54 55 - resp = session.MakeRequest(t, NewRequestWithValues(t, "POST", baseurl+"/gitea/1", map[string]string{"_csrf": csrfToken}), http.StatusUnprocessableEntity) 55 + resp = session.MakeRequest(t, NewRequestWithValues(t, "POST", baseurl+"/1", map[string]string{"_csrf": csrfToken}), http.StatusUnprocessableEntity) 56 56 htmlDoc = NewHTMLParser(t, resp.Body) 57 57 assert.Equal(t, webhooksLen, htmlDoc.Find(`a[href^="`+baseurl+`/"][href$="/new"]`).Length(), "not all webhooks are listed in the 'new' dropdown on failure") 58 58 } ··· 330 330 } 331 331 } 332 332 333 - session.MakeRequest(t, NewRequestWithValues(t, "POST", "/user2/repo1/settings/hooks/"+name+"/new", payload), http.StatusUnprocessableEntity) 333 + resp := session.MakeRequest(t, NewRequestWithValues(t, "POST", "/user2/repo1/settings/hooks/"+name+"/new", payload), http.StatusUnprocessableEntity) 334 + // check that the invalid form is pre-filled 335 + htmlForm = NewHTMLParser(t, resp.Body).Find(`form[action^="/user2/repo1/settings/hooks/"]`) 336 + for k, v := range payload { 337 + if k == "_csrf" || k == "events" || v == "" { 338 + // the 'events' is a radio input, which is buggy below 339 + continue 340 + } 341 + assert.Equal(t, v, assertInput(t, htmlForm, k), "input %q did not contain value %q", k, v) 342 + } 334 343 if t.Failed() { 335 344 t.Log(invalidPatch) 336 345 }