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