code.gitea.io/gitea@v1.21.7/routers/web/repo/setting/webhook.go (about) 1 // Copyright 2015 The Gogs Authors. All rights reserved. 2 // Copyright 2017 The Gitea Authors. All rights reserved. 3 // SPDX-License-Identifier: MIT 4 5 package setting 6 7 import ( 8 "errors" 9 "fmt" 10 "net/http" 11 "net/url" 12 "path" 13 "strings" 14 15 "code.gitea.io/gitea/models/perm" 16 access_model "code.gitea.io/gitea/models/perm/access" 17 user_model "code.gitea.io/gitea/models/user" 18 "code.gitea.io/gitea/models/webhook" 19 "code.gitea.io/gitea/modules/base" 20 "code.gitea.io/gitea/modules/context" 21 "code.gitea.io/gitea/modules/git" 22 "code.gitea.io/gitea/modules/json" 23 "code.gitea.io/gitea/modules/setting" 24 api "code.gitea.io/gitea/modules/structs" 25 "code.gitea.io/gitea/modules/util" 26 "code.gitea.io/gitea/modules/web" 27 webhook_module "code.gitea.io/gitea/modules/webhook" 28 "code.gitea.io/gitea/services/convert" 29 "code.gitea.io/gitea/services/forms" 30 webhook_service "code.gitea.io/gitea/services/webhook" 31 ) 32 33 const ( 34 tplHooks base.TplName = "repo/settings/webhook/base" 35 tplHookNew base.TplName = "repo/settings/webhook/new" 36 tplOrgHookNew base.TplName = "org/settings/hook_new" 37 tplUserHookNew base.TplName = "user/settings/hook_new" 38 tplAdminHookNew base.TplName = "admin/hook_new" 39 ) 40 41 // Webhooks render web hooks list page 42 func Webhooks(ctx *context.Context) { 43 ctx.Data["Title"] = ctx.Tr("repo.settings.hooks") 44 ctx.Data["PageIsSettingsHooks"] = true 45 ctx.Data["BaseLink"] = ctx.Repo.RepoLink + "/settings/hooks" 46 ctx.Data["BaseLinkNew"] = ctx.Repo.RepoLink + "/settings/hooks" 47 ctx.Data["Description"] = ctx.Tr("repo.settings.hooks_desc", "https://docs.gitea.com/usage/webhooks") 48 49 ws, err := webhook.ListWebhooksByOpts(ctx, &webhook.ListWebhookOptions{RepoID: ctx.Repo.Repository.ID}) 50 if err != nil { 51 ctx.ServerError("GetWebhooksByRepoID", err) 52 return 53 } 54 ctx.Data["Webhooks"] = ws 55 56 ctx.HTML(http.StatusOK, tplHooks) 57 } 58 59 type ownerRepoCtx struct { 60 OwnerID int64 61 RepoID int64 62 IsAdmin bool 63 IsSystemWebhook bool 64 Link string 65 LinkNew string 66 NewTemplate base.TplName 67 } 68 69 // getOwnerRepoCtx determines whether this is a repo, owner, or admin (both default and system) context. 70 func getOwnerRepoCtx(ctx *context.Context) (*ownerRepoCtx, error) { 71 if ctx.Data["PageIsRepoSettings"] == true { 72 return &ownerRepoCtx{ 73 RepoID: ctx.Repo.Repository.ID, 74 Link: path.Join(ctx.Repo.RepoLink, "settings/hooks"), 75 LinkNew: path.Join(ctx.Repo.RepoLink, "settings/hooks"), 76 NewTemplate: tplHookNew, 77 }, nil 78 } 79 80 if ctx.Data["PageIsOrgSettings"] == true { 81 return &ownerRepoCtx{ 82 OwnerID: ctx.ContextUser.ID, 83 Link: path.Join(ctx.Org.OrgLink, "settings/hooks"), 84 LinkNew: path.Join(ctx.Org.OrgLink, "settings/hooks"), 85 NewTemplate: tplOrgHookNew, 86 }, nil 87 } 88 89 if ctx.Data["PageIsUserSettings"] == true { 90 return &ownerRepoCtx{ 91 OwnerID: ctx.Doer.ID, 92 Link: path.Join(setting.AppSubURL, "/user/settings/hooks"), 93 LinkNew: path.Join(setting.AppSubURL, "/user/settings/hooks"), 94 NewTemplate: tplUserHookNew, 95 }, nil 96 } 97 98 if ctx.Data["PageIsAdmin"] == true { 99 return &ownerRepoCtx{ 100 IsAdmin: true, 101 IsSystemWebhook: ctx.Params(":configType") == "system-hooks", 102 Link: path.Join(setting.AppSubURL, "/admin/hooks"), 103 LinkNew: path.Join(setting.AppSubURL, "/admin/", ctx.Params(":configType")), 104 NewTemplate: tplAdminHookNew, 105 }, nil 106 } 107 108 return nil, errors.New("unable to set OwnerRepo context") 109 } 110 111 func checkHookType(ctx *context.Context) string { 112 hookType := strings.ToLower(ctx.Params(":type")) 113 if !util.SliceContainsString(setting.Webhook.Types, hookType, true) { 114 ctx.NotFound("checkHookType", nil) 115 return "" 116 } 117 return hookType 118 } 119 120 // WebhooksNew render creating webhook page 121 func WebhooksNew(ctx *context.Context) { 122 ctx.Data["Title"] = ctx.Tr("repo.settings.add_webhook") 123 ctx.Data["Webhook"] = webhook.Webhook{HookEvent: &webhook_module.HookEvent{}} 124 125 orCtx, err := getOwnerRepoCtx(ctx) 126 if err != nil { 127 ctx.ServerError("getOwnerRepoCtx", err) 128 return 129 } 130 131 if orCtx.IsAdmin && orCtx.IsSystemWebhook { 132 ctx.Data["PageIsAdminSystemHooks"] = true 133 ctx.Data["PageIsAdminSystemHooksNew"] = true 134 } else if orCtx.IsAdmin { 135 ctx.Data["PageIsAdminDefaultHooks"] = true 136 ctx.Data["PageIsAdminDefaultHooksNew"] = true 137 } else { 138 ctx.Data["PageIsSettingsHooks"] = true 139 ctx.Data["PageIsSettingsHooksNew"] = true 140 } 141 142 hookType := checkHookType(ctx) 143 ctx.Data["HookType"] = hookType 144 if ctx.Written() { 145 return 146 } 147 if hookType == "discord" { 148 ctx.Data["DiscordHook"] = map[string]any{ 149 "Username": "Gitea", 150 } 151 } 152 ctx.Data["BaseLink"] = orCtx.LinkNew 153 154 ctx.HTML(http.StatusOK, orCtx.NewTemplate) 155 } 156 157 // ParseHookEvent convert web form content to webhook.HookEvent 158 func ParseHookEvent(form forms.WebhookForm) *webhook_module.HookEvent { 159 return &webhook_module.HookEvent{ 160 PushOnly: form.PushOnly(), 161 SendEverything: form.SendEverything(), 162 ChooseEvents: form.ChooseEvents(), 163 HookEvents: webhook_module.HookEvents{ 164 Create: form.Create, 165 Delete: form.Delete, 166 Fork: form.Fork, 167 Issues: form.Issues, 168 IssueAssign: form.IssueAssign, 169 IssueLabel: form.IssueLabel, 170 IssueMilestone: form.IssueMilestone, 171 IssueComment: form.IssueComment, 172 Release: form.Release, 173 Push: form.Push, 174 PullRequest: form.PullRequest, 175 PullRequestAssign: form.PullRequestAssign, 176 PullRequestLabel: form.PullRequestLabel, 177 PullRequestMilestone: form.PullRequestMilestone, 178 PullRequestComment: form.PullRequestComment, 179 PullRequestReview: form.PullRequestReview, 180 PullRequestSync: form.PullRequestSync, 181 PullRequestReviewRequest: form.PullRequestReviewRequest, 182 Wiki: form.Wiki, 183 Repository: form.Repository, 184 Package: form.Package, 185 }, 186 BranchFilter: form.BranchFilter, 187 } 188 } 189 190 type webhookParams struct { 191 // Type should be imported from webhook package (webhook.XXX) 192 Type string 193 194 URL string 195 ContentType webhook.HookContentType 196 Secret string 197 HTTPMethod string 198 WebhookForm forms.WebhookForm 199 Meta any 200 } 201 202 func createWebhook(ctx *context.Context, params webhookParams) { 203 ctx.Data["Title"] = ctx.Tr("repo.settings.add_webhook") 204 ctx.Data["PageIsSettingsHooks"] = true 205 ctx.Data["PageIsSettingsHooksNew"] = true 206 ctx.Data["Webhook"] = webhook.Webhook{HookEvent: &webhook_module.HookEvent{}} 207 ctx.Data["HookType"] = params.Type 208 209 orCtx, err := getOwnerRepoCtx(ctx) 210 if err != nil { 211 ctx.ServerError("getOwnerRepoCtx", err) 212 return 213 } 214 ctx.Data["BaseLink"] = orCtx.LinkNew 215 216 if ctx.HasError() { 217 ctx.HTML(http.StatusOK, orCtx.NewTemplate) 218 return 219 } 220 221 var meta []byte 222 if params.Meta != nil { 223 meta, err = json.Marshal(params.Meta) 224 if err != nil { 225 ctx.ServerError("Marshal", err) 226 return 227 } 228 } 229 230 w := &webhook.Webhook{ 231 RepoID: orCtx.RepoID, 232 URL: params.URL, 233 HTTPMethod: params.HTTPMethod, 234 ContentType: params.ContentType, 235 Secret: params.Secret, 236 HookEvent: ParseHookEvent(params.WebhookForm), 237 IsActive: params.WebhookForm.Active, 238 Type: params.Type, 239 Meta: string(meta), 240 OwnerID: orCtx.OwnerID, 241 IsSystemWebhook: orCtx.IsSystemWebhook, 242 } 243 err = w.SetHeaderAuthorization(params.WebhookForm.AuthorizationHeader) 244 if err != nil { 245 ctx.ServerError("SetHeaderAuthorization", err) 246 return 247 } 248 if err := w.UpdateEvent(); err != nil { 249 ctx.ServerError("UpdateEvent", err) 250 return 251 } else if err := webhook.CreateWebhook(ctx, w); err != nil { 252 ctx.ServerError("CreateWebhook", err) 253 return 254 } 255 256 ctx.Flash.Success(ctx.Tr("repo.settings.add_hook_success")) 257 ctx.Redirect(orCtx.Link) 258 } 259 260 func editWebhook(ctx *context.Context, params webhookParams) { 261 ctx.Data["Title"] = ctx.Tr("repo.settings.update_webhook") 262 ctx.Data["PageIsSettingsHooks"] = true 263 ctx.Data["PageIsSettingsHooksEdit"] = true 264 265 orCtx, w := checkWebhook(ctx) 266 if ctx.Written() { 267 return 268 } 269 ctx.Data["Webhook"] = w 270 271 if ctx.HasError() { 272 ctx.HTML(http.StatusOK, orCtx.NewTemplate) 273 return 274 } 275 276 var meta []byte 277 var err error 278 if params.Meta != nil { 279 meta, err = json.Marshal(params.Meta) 280 if err != nil { 281 ctx.ServerError("Marshal", err) 282 return 283 } 284 } 285 286 w.URL = params.URL 287 w.ContentType = params.ContentType 288 w.Secret = params.Secret 289 w.HookEvent = ParseHookEvent(params.WebhookForm) 290 w.IsActive = params.WebhookForm.Active 291 w.HTTPMethod = params.HTTPMethod 292 w.Meta = string(meta) 293 294 err = w.SetHeaderAuthorization(params.WebhookForm.AuthorizationHeader) 295 if err != nil { 296 ctx.ServerError("SetHeaderAuthorization", err) 297 return 298 } 299 300 if err := w.UpdateEvent(); err != nil { 301 ctx.ServerError("UpdateEvent", err) 302 return 303 } else if err := webhook.UpdateWebhook(w); err != nil { 304 ctx.ServerError("UpdateWebhook", err) 305 return 306 } 307 308 ctx.Flash.Success(ctx.Tr("repo.settings.update_hook_success")) 309 ctx.Redirect(fmt.Sprintf("%s/%d", orCtx.Link, w.ID)) 310 } 311 312 // GiteaHooksNewPost response for creating Gitea webhook 313 func GiteaHooksNewPost(ctx *context.Context) { 314 createWebhook(ctx, giteaHookParams(ctx)) 315 } 316 317 // GiteaHooksEditPost response for editing Gitea webhook 318 func GiteaHooksEditPost(ctx *context.Context) { 319 editWebhook(ctx, giteaHookParams(ctx)) 320 } 321 322 func giteaHookParams(ctx *context.Context) webhookParams { 323 form := web.GetForm(ctx).(*forms.NewWebhookForm) 324 325 contentType := webhook.ContentTypeJSON 326 if webhook.HookContentType(form.ContentType) == webhook.ContentTypeForm { 327 contentType = webhook.ContentTypeForm 328 } 329 330 return webhookParams{ 331 Type: webhook_module.GITEA, 332 URL: form.PayloadURL, 333 ContentType: contentType, 334 Secret: form.Secret, 335 HTTPMethod: form.HTTPMethod, 336 WebhookForm: form.WebhookForm, 337 } 338 } 339 340 // GogsHooksNewPost response for creating Gogs webhook 341 func GogsHooksNewPost(ctx *context.Context) { 342 createWebhook(ctx, gogsHookParams(ctx)) 343 } 344 345 // GogsHooksEditPost response for editing Gogs webhook 346 func GogsHooksEditPost(ctx *context.Context) { 347 editWebhook(ctx, gogsHookParams(ctx)) 348 } 349 350 func gogsHookParams(ctx *context.Context) webhookParams { 351 form := web.GetForm(ctx).(*forms.NewGogshookForm) 352 353 contentType := webhook.ContentTypeJSON 354 if webhook.HookContentType(form.ContentType) == webhook.ContentTypeForm { 355 contentType = webhook.ContentTypeForm 356 } 357 358 return webhookParams{ 359 Type: webhook_module.GOGS, 360 URL: form.PayloadURL, 361 ContentType: contentType, 362 Secret: form.Secret, 363 WebhookForm: form.WebhookForm, 364 } 365 } 366 367 // DiscordHooksNewPost response for creating Discord webhook 368 func DiscordHooksNewPost(ctx *context.Context) { 369 createWebhook(ctx, discordHookParams(ctx)) 370 } 371 372 // DiscordHooksEditPost response for editing Discord webhook 373 func DiscordHooksEditPost(ctx *context.Context) { 374 editWebhook(ctx, discordHookParams(ctx)) 375 } 376 377 func discordHookParams(ctx *context.Context) webhookParams { 378 form := web.GetForm(ctx).(*forms.NewDiscordHookForm) 379 380 return webhookParams{ 381 Type: webhook_module.DISCORD, 382 URL: form.PayloadURL, 383 ContentType: webhook.ContentTypeJSON, 384 WebhookForm: form.WebhookForm, 385 Meta: &webhook_service.DiscordMeta{ 386 Username: form.Username, 387 IconURL: form.IconURL, 388 }, 389 } 390 } 391 392 // DingtalkHooksNewPost response for creating Dingtalk webhook 393 func DingtalkHooksNewPost(ctx *context.Context) { 394 createWebhook(ctx, dingtalkHookParams(ctx)) 395 } 396 397 // DingtalkHooksEditPost response for editing Dingtalk webhook 398 func DingtalkHooksEditPost(ctx *context.Context) { 399 editWebhook(ctx, dingtalkHookParams(ctx)) 400 } 401 402 func dingtalkHookParams(ctx *context.Context) webhookParams { 403 form := web.GetForm(ctx).(*forms.NewDingtalkHookForm) 404 405 return webhookParams{ 406 Type: webhook_module.DINGTALK, 407 URL: form.PayloadURL, 408 ContentType: webhook.ContentTypeJSON, 409 WebhookForm: form.WebhookForm, 410 } 411 } 412 413 // TelegramHooksNewPost response for creating Telegram webhook 414 func TelegramHooksNewPost(ctx *context.Context) { 415 createWebhook(ctx, telegramHookParams(ctx)) 416 } 417 418 // TelegramHooksEditPost response for editing Telegram webhook 419 func TelegramHooksEditPost(ctx *context.Context) { 420 editWebhook(ctx, telegramHookParams(ctx)) 421 } 422 423 func telegramHookParams(ctx *context.Context) webhookParams { 424 form := web.GetForm(ctx).(*forms.NewTelegramHookForm) 425 426 return webhookParams{ 427 Type: webhook_module.TELEGRAM, 428 URL: fmt.Sprintf("https://api.telegram.org/bot%s/sendMessage?chat_id=%s&message_thread_id=%s", url.PathEscape(form.BotToken), url.QueryEscape(form.ChatID), url.QueryEscape(form.ThreadID)), 429 ContentType: webhook.ContentTypeJSON, 430 WebhookForm: form.WebhookForm, 431 Meta: &webhook_service.TelegramMeta{ 432 BotToken: form.BotToken, 433 ChatID: form.ChatID, 434 ThreadID: form.ThreadID, 435 }, 436 } 437 } 438 439 // MatrixHooksNewPost response for creating Matrix webhook 440 func MatrixHooksNewPost(ctx *context.Context) { 441 createWebhook(ctx, matrixHookParams(ctx)) 442 } 443 444 // MatrixHooksEditPost response for editing Matrix webhook 445 func MatrixHooksEditPost(ctx *context.Context) { 446 editWebhook(ctx, matrixHookParams(ctx)) 447 } 448 449 func matrixHookParams(ctx *context.Context) webhookParams { 450 form := web.GetForm(ctx).(*forms.NewMatrixHookForm) 451 452 return webhookParams{ 453 Type: webhook_module.MATRIX, 454 URL: fmt.Sprintf("%s/_matrix/client/r0/rooms/%s/send/m.room.message", form.HomeserverURL, url.PathEscape(form.RoomID)), 455 ContentType: webhook.ContentTypeJSON, 456 HTTPMethod: http.MethodPut, 457 WebhookForm: form.WebhookForm, 458 Meta: &webhook_service.MatrixMeta{ 459 HomeserverURL: form.HomeserverURL, 460 Room: form.RoomID, 461 MessageType: form.MessageType, 462 }, 463 } 464 } 465 466 // MSTeamsHooksNewPost response for creating MSTeams webhook 467 func MSTeamsHooksNewPost(ctx *context.Context) { 468 createWebhook(ctx, mSTeamsHookParams(ctx)) 469 } 470 471 // MSTeamsHooksEditPost response for editing MSTeams webhook 472 func MSTeamsHooksEditPost(ctx *context.Context) { 473 editWebhook(ctx, mSTeamsHookParams(ctx)) 474 } 475 476 func mSTeamsHookParams(ctx *context.Context) webhookParams { 477 form := web.GetForm(ctx).(*forms.NewMSTeamsHookForm) 478 479 return webhookParams{ 480 Type: webhook_module.MSTEAMS, 481 URL: form.PayloadURL, 482 ContentType: webhook.ContentTypeJSON, 483 WebhookForm: form.WebhookForm, 484 } 485 } 486 487 // SlackHooksNewPost response for creating Slack webhook 488 func SlackHooksNewPost(ctx *context.Context) { 489 createWebhook(ctx, slackHookParams(ctx)) 490 } 491 492 // SlackHooksEditPost response for editing Slack webhook 493 func SlackHooksEditPost(ctx *context.Context) { 494 editWebhook(ctx, slackHookParams(ctx)) 495 } 496 497 func slackHookParams(ctx *context.Context) webhookParams { 498 form := web.GetForm(ctx).(*forms.NewSlackHookForm) 499 500 return webhookParams{ 501 Type: webhook_module.SLACK, 502 URL: form.PayloadURL, 503 ContentType: webhook.ContentTypeJSON, 504 WebhookForm: form.WebhookForm, 505 Meta: &webhook_service.SlackMeta{ 506 Channel: strings.TrimSpace(form.Channel), 507 Username: form.Username, 508 IconURL: form.IconURL, 509 Color: form.Color, 510 }, 511 } 512 } 513 514 // FeishuHooksNewPost response for creating Feishu webhook 515 func FeishuHooksNewPost(ctx *context.Context) { 516 createWebhook(ctx, feishuHookParams(ctx)) 517 } 518 519 // FeishuHooksEditPost response for editing Feishu webhook 520 func FeishuHooksEditPost(ctx *context.Context) { 521 editWebhook(ctx, feishuHookParams(ctx)) 522 } 523 524 func feishuHookParams(ctx *context.Context) webhookParams { 525 form := web.GetForm(ctx).(*forms.NewFeishuHookForm) 526 527 return webhookParams{ 528 Type: webhook_module.FEISHU, 529 URL: form.PayloadURL, 530 ContentType: webhook.ContentTypeJSON, 531 WebhookForm: form.WebhookForm, 532 } 533 } 534 535 // WechatworkHooksNewPost response for creating Wechatwork webhook 536 func WechatworkHooksNewPost(ctx *context.Context) { 537 createWebhook(ctx, wechatworkHookParams(ctx)) 538 } 539 540 // WechatworkHooksEditPost response for editing Wechatwork webhook 541 func WechatworkHooksEditPost(ctx *context.Context) { 542 editWebhook(ctx, wechatworkHookParams(ctx)) 543 } 544 545 func wechatworkHookParams(ctx *context.Context) webhookParams { 546 form := web.GetForm(ctx).(*forms.NewWechatWorkHookForm) 547 548 return webhookParams{ 549 Type: webhook_module.WECHATWORK, 550 URL: form.PayloadURL, 551 ContentType: webhook.ContentTypeJSON, 552 WebhookForm: form.WebhookForm, 553 } 554 } 555 556 // PackagistHooksNewPost response for creating Packagist webhook 557 func PackagistHooksNewPost(ctx *context.Context) { 558 createWebhook(ctx, packagistHookParams(ctx)) 559 } 560 561 // PackagistHooksEditPost response for editing Packagist webhook 562 func PackagistHooksEditPost(ctx *context.Context) { 563 editWebhook(ctx, packagistHookParams(ctx)) 564 } 565 566 func packagistHookParams(ctx *context.Context) webhookParams { 567 form := web.GetForm(ctx).(*forms.NewPackagistHookForm) 568 569 return webhookParams{ 570 Type: webhook_module.PACKAGIST, 571 URL: fmt.Sprintf("https://packagist.org/api/update-package?username=%s&apiToken=%s", url.QueryEscape(form.Username), url.QueryEscape(form.APIToken)), 572 ContentType: webhook.ContentTypeJSON, 573 WebhookForm: form.WebhookForm, 574 Meta: &webhook_service.PackagistMeta{ 575 Username: form.Username, 576 APIToken: form.APIToken, 577 PackageURL: form.PackageURL, 578 }, 579 } 580 } 581 582 func checkWebhook(ctx *context.Context) (*ownerRepoCtx, *webhook.Webhook) { 583 orCtx, err := getOwnerRepoCtx(ctx) 584 if err != nil { 585 ctx.ServerError("getOwnerRepoCtx", err) 586 return nil, nil 587 } 588 ctx.Data["BaseLink"] = orCtx.Link 589 590 var w *webhook.Webhook 591 if orCtx.RepoID > 0 { 592 w, err = webhook.GetWebhookByRepoID(ctx, orCtx.RepoID, ctx.ParamsInt64(":id")) 593 } else if orCtx.OwnerID > 0 { 594 w, err = webhook.GetWebhookByOwnerID(ctx, orCtx.OwnerID, ctx.ParamsInt64(":id")) 595 } else if orCtx.IsAdmin { 596 w, err = webhook.GetSystemOrDefaultWebhook(ctx, ctx.ParamsInt64(":id")) 597 } 598 if err != nil || w == nil { 599 if webhook.IsErrWebhookNotExist(err) { 600 ctx.NotFound("GetWebhookByID", nil) 601 } else { 602 ctx.ServerError("GetWebhookByID", err) 603 } 604 return nil, nil 605 } 606 607 ctx.Data["HookType"] = w.Type 608 switch w.Type { 609 case webhook_module.SLACK: 610 ctx.Data["SlackHook"] = webhook_service.GetSlackHook(w) 611 case webhook_module.DISCORD: 612 ctx.Data["DiscordHook"] = webhook_service.GetDiscordHook(w) 613 case webhook_module.TELEGRAM: 614 ctx.Data["TelegramHook"] = webhook_service.GetTelegramHook(w) 615 case webhook_module.MATRIX: 616 ctx.Data["MatrixHook"] = webhook_service.GetMatrixHook(w) 617 case webhook_module.PACKAGIST: 618 ctx.Data["PackagistHook"] = webhook_service.GetPackagistHook(w) 619 } 620 621 ctx.Data["History"], err = w.History(1) 622 if err != nil { 623 ctx.ServerError("History", err) 624 } 625 return orCtx, w 626 } 627 628 // WebHooksEdit render editing web hook page 629 func WebHooksEdit(ctx *context.Context) { 630 ctx.Data["Title"] = ctx.Tr("repo.settings.update_webhook") 631 ctx.Data["PageIsSettingsHooks"] = true 632 ctx.Data["PageIsSettingsHooksEdit"] = true 633 634 orCtx, w := checkWebhook(ctx) 635 if ctx.Written() { 636 return 637 } 638 ctx.Data["Webhook"] = w 639 640 ctx.HTML(http.StatusOK, orCtx.NewTemplate) 641 } 642 643 // TestWebhook test if web hook is work fine 644 func TestWebhook(ctx *context.Context) { 645 hookID := ctx.ParamsInt64(":id") 646 w, err := webhook.GetWebhookByRepoID(ctx, ctx.Repo.Repository.ID, hookID) 647 if err != nil { 648 ctx.Flash.Error("GetWebhookByRepoID: " + err.Error()) 649 ctx.Status(http.StatusInternalServerError) 650 return 651 } 652 653 // Grab latest commit or fake one if it's empty repository. 654 commit := ctx.Repo.Commit 655 if commit == nil { 656 ghost := user_model.NewGhostUser() 657 commit = &git.Commit{ 658 ID: git.MustIDFromString(git.EmptySHA), 659 Author: ghost.NewGitSig(), 660 Committer: ghost.NewGitSig(), 661 CommitMessage: "This is a fake commit", 662 } 663 } 664 665 apiUser := convert.ToUserWithAccessMode(ctx, ctx.Doer, perm.AccessModeNone) 666 667 apiCommit := &api.PayloadCommit{ 668 ID: commit.ID.String(), 669 Message: commit.Message(), 670 URL: ctx.Repo.Repository.HTMLURL() + "/commit/" + url.PathEscape(commit.ID.String()), 671 Author: &api.PayloadUser{ 672 Name: commit.Author.Name, 673 Email: commit.Author.Email, 674 }, 675 Committer: &api.PayloadUser{ 676 Name: commit.Committer.Name, 677 Email: commit.Committer.Email, 678 }, 679 } 680 681 commitID := commit.ID.String() 682 p := &api.PushPayload{ 683 Ref: git.BranchPrefix + ctx.Repo.Repository.DefaultBranch, 684 Before: commitID, 685 After: commitID, 686 CompareURL: setting.AppURL + ctx.Repo.Repository.ComposeCompareURL(commitID, commitID), 687 Commits: []*api.PayloadCommit{apiCommit}, 688 TotalCommits: 1, 689 HeadCommit: apiCommit, 690 Repo: convert.ToRepo(ctx, ctx.Repo.Repository, access_model.Permission{AccessMode: perm.AccessModeNone}), 691 Pusher: apiUser, 692 Sender: apiUser, 693 } 694 if err := webhook_service.PrepareWebhook(ctx, w, webhook_module.HookEventPush, p); err != nil { 695 ctx.Flash.Error("PrepareWebhook: " + err.Error()) 696 ctx.Status(http.StatusInternalServerError) 697 } else { 698 ctx.Flash.Info(ctx.Tr("repo.settings.webhook.delivery.success")) 699 ctx.Status(http.StatusOK) 700 } 701 } 702 703 // ReplayWebhook replays a webhook 704 func ReplayWebhook(ctx *context.Context) { 705 hookTaskUUID := ctx.Params(":uuid") 706 707 orCtx, w := checkWebhook(ctx) 708 if ctx.Written() { 709 return 710 } 711 712 if err := webhook_service.ReplayHookTask(ctx, w, hookTaskUUID); err != nil { 713 if webhook.IsErrHookTaskNotExist(err) { 714 ctx.NotFound("ReplayHookTask", nil) 715 } else { 716 ctx.ServerError("ReplayHookTask", err) 717 } 718 return 719 } 720 721 ctx.Flash.Success(ctx.Tr("repo.settings.webhook.delivery.success")) 722 ctx.Redirect(fmt.Sprintf("%s/%d", orCtx.Link, w.ID)) 723 } 724 725 // DeleteWebhook delete a webhook 726 func DeleteWebhook(ctx *context.Context) { 727 if err := webhook.DeleteWebhookByRepoID(ctx, ctx.Repo.Repository.ID, ctx.FormInt64("id")); err != nil { 728 ctx.Flash.Error("DeleteWebhookByRepoID: " + err.Error()) 729 } else { 730 ctx.Flash.Success(ctx.Tr("repo.settings.webhook_deletion_success")) 731 } 732 733 ctx.JSONRedirect(ctx.Repo.RepoLink + "/settings/hooks") 734 }