gitea源码

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. // Copyright 2020 The Gitea Authors. All rights reserved.
  2. // SPDX-License-Identifier: MIT
  3. package webhook
  4. import (
  5. "bytes"
  6. "fmt"
  7. "net/http"
  8. webhook_model "code.gitea.io/gitea/models/webhook"
  9. "code.gitea.io/gitea/modules/json"
  10. api "code.gitea.io/gitea/modules/structs"
  11. webhook_module "code.gitea.io/gitea/modules/webhook"
  12. )
  13. // payloadConvertor defines the interface to convert system payload to webhook payload
  14. type payloadConvertor[T any] interface {
  15. Create(*api.CreatePayload) (T, error)
  16. Delete(*api.DeletePayload) (T, error)
  17. Fork(*api.ForkPayload) (T, error)
  18. Issue(*api.IssuePayload) (T, error)
  19. IssueComment(*api.IssueCommentPayload) (T, error)
  20. Push(*api.PushPayload) (T, error)
  21. PullRequest(*api.PullRequestPayload) (T, error)
  22. Review(*api.PullRequestPayload, webhook_module.HookEventType) (T, error)
  23. Repository(*api.RepositoryPayload) (T, error)
  24. Release(*api.ReleasePayload) (T, error)
  25. Wiki(*api.WikiPayload) (T, error)
  26. Package(*api.PackagePayload) (T, error)
  27. Status(*api.CommitStatusPayload) (T, error)
  28. WorkflowRun(*api.WorkflowRunPayload) (T, error)
  29. WorkflowJob(*api.WorkflowJobPayload) (T, error)
  30. }
  31. func convertUnmarshalledJSON[T, P any](convert func(P) (T, error), data []byte) (t T, err error) {
  32. var p P
  33. if err = json.Unmarshal(data, &p); err != nil {
  34. return t, fmt.Errorf("could not unmarshal payload: %w", err)
  35. }
  36. return convert(p)
  37. }
  38. func newPayload[T any](rc payloadConvertor[T], data []byte, event webhook_module.HookEventType) (t T, err error) {
  39. switch event {
  40. case webhook_module.HookEventCreate:
  41. return convertUnmarshalledJSON(rc.Create, data)
  42. case webhook_module.HookEventDelete:
  43. return convertUnmarshalledJSON(rc.Delete, data)
  44. case webhook_module.HookEventFork:
  45. return convertUnmarshalledJSON(rc.Fork, data)
  46. case webhook_module.HookEventIssues, webhook_module.HookEventIssueAssign, webhook_module.HookEventIssueLabel, webhook_module.HookEventIssueMilestone:
  47. return convertUnmarshalledJSON(rc.Issue, data)
  48. case webhook_module.HookEventIssueComment, webhook_module.HookEventPullRequestComment:
  49. // previous code sometimes sent s.PullRequest(p.(*api.PullRequestPayload))
  50. // however I couldn't find in notifier.go such a payload with an HookEvent***Comment event
  51. // History (most recent first):
  52. // - refactored in https://github.com/go-gitea/gitea/pull/12310
  53. // - assertion added in https://github.com/go-gitea/gitea/pull/12046
  54. // - issue raised in https://github.com/go-gitea/gitea/issues/11940#issuecomment-645713996
  55. // > That's because for HookEventPullRequestComment event, some places use IssueCommentPayload and others use PullRequestPayload
  56. // In modules/actions/workflows.go:183 the type assertion is always payload.(*api.IssueCommentPayload)
  57. return convertUnmarshalledJSON(rc.IssueComment, data)
  58. case webhook_module.HookEventPush:
  59. return convertUnmarshalledJSON(rc.Push, data)
  60. case webhook_module.HookEventPullRequest, webhook_module.HookEventPullRequestAssign, webhook_module.HookEventPullRequestLabel,
  61. webhook_module.HookEventPullRequestMilestone, webhook_module.HookEventPullRequestSync, webhook_module.HookEventPullRequestReviewRequest:
  62. return convertUnmarshalledJSON(rc.PullRequest, data)
  63. case webhook_module.HookEventPullRequestReviewApproved, webhook_module.HookEventPullRequestReviewRejected, webhook_module.HookEventPullRequestReviewComment:
  64. return convertUnmarshalledJSON(func(p *api.PullRequestPayload) (T, error) {
  65. return rc.Review(p, event)
  66. }, data)
  67. case webhook_module.HookEventRepository:
  68. return convertUnmarshalledJSON(rc.Repository, data)
  69. case webhook_module.HookEventRelease:
  70. return convertUnmarshalledJSON(rc.Release, data)
  71. case webhook_module.HookEventWiki:
  72. return convertUnmarshalledJSON(rc.Wiki, data)
  73. case webhook_module.HookEventPackage:
  74. return convertUnmarshalledJSON(rc.Package, data)
  75. case webhook_module.HookEventStatus:
  76. return convertUnmarshalledJSON(rc.Status, data)
  77. case webhook_module.HookEventWorkflowRun:
  78. return convertUnmarshalledJSON(rc.WorkflowRun, data)
  79. case webhook_module.HookEventWorkflowJob:
  80. return convertUnmarshalledJSON(rc.WorkflowJob, data)
  81. }
  82. return t, fmt.Errorf("newPayload unsupported event: %s", event)
  83. }
  84. func newJSONRequest[T any](pc payloadConvertor[T], w *webhook_model.Webhook, t *webhook_model.HookTask, withDefaultHeaders bool) (*http.Request, []byte, error) {
  85. payload, err := newPayload(pc, []byte(t.PayloadContent), t.EventType)
  86. if err != nil {
  87. return nil, nil, err
  88. }
  89. return prepareJSONRequest(payload, w, t, withDefaultHeaders)
  90. }
  91. func prepareJSONRequest[T any](payload T, w *webhook_model.Webhook, t *webhook_model.HookTask, withDefaultHeaders bool) (*http.Request, []byte, error) {
  92. body, err := json.MarshalIndent(payload, "", " ")
  93. if err != nil {
  94. return nil, nil, err
  95. }
  96. method := w.HTTPMethod
  97. if method == "" {
  98. method = http.MethodPost
  99. }
  100. req, err := http.NewRequest(method, w.URL, bytes.NewReader(body))
  101. if err != nil {
  102. return nil, nil, err
  103. }
  104. req.Header.Set("Content-Type", "application/json")
  105. if withDefaultHeaders {
  106. return req, body, addDefaultHeaders(req, []byte(w.Secret), w, t, body)
  107. }
  108. return req, body, nil
  109. }