2020-09-05 10:57:13 +08:00
// Copyright 2020 The Gitea Authors. All rights reserved.
2022-11-27 13:20:29 -05:00
// SPDX-License-Identifier: MIT
2020-09-05 10:57:13 +08:00
package webhook
import (
2024-03-07 23:18:38 +01:00
"bytes"
"fmt"
"net/http"
webhook_model "code.gitea.io/gitea/models/webhook"
"code.gitea.io/gitea/modules/json"
2020-09-05 10:57:13 +08:00
api "code.gitea.io/gitea/modules/structs"
2023-01-01 16:23:15 +01:00
webhook_module "code.gitea.io/gitea/modules/webhook"
2020-09-05 10:57:13 +08:00
)
2024-03-07 23:18:38 +01:00
// payloadConvertor defines the interface to convert system payload to webhook payload
type payloadConvertor [ T any ] interface {
Create ( * api . CreatePayload ) ( T , error )
Delete ( * api . DeletePayload ) ( T , error )
Fork ( * api . ForkPayload ) ( T , error )
Issue ( * api . IssuePayload ) ( T , error )
IssueComment ( * api . IssueCommentPayload ) ( T , error )
Push ( * api . PushPayload ) ( T , error )
PullRequest ( * api . PullRequestPayload ) ( T , error )
Review ( * api . PullRequestPayload , webhook_module . HookEventType ) ( T , error )
Repository ( * api . RepositoryPayload ) ( T , error )
Release ( * api . ReleasePayload ) ( T , error )
Wiki ( * api . WikiPayload ) ( T , error )
Package ( * api . PackagePayload ) ( T , error )
}
func convertUnmarshalledJSON [ T , P any ] ( convert func ( P ) ( T , error ) , data [ ] byte ) ( T , error ) {
var p P
if err := json . Unmarshal ( data , & p ) ; err != nil {
var t T
return t , fmt . Errorf ( "could not unmarshal payload: %w" , err )
}
return convert ( p )
2020-09-05 10:57:13 +08:00
}
2024-03-07 23:18:38 +01:00
func newPayload [ T any ] ( rc payloadConvertor [ T ] , data [ ] byte , event webhook_module . HookEventType ) ( T , error ) {
2020-09-05 10:57:13 +08:00
switch event {
2023-01-01 16:23:15 +01:00
case webhook_module . HookEventCreate :
2024-03-07 23:18:38 +01:00
return convertUnmarshalledJSON ( rc . Create , data )
2023-01-01 16:23:15 +01:00
case webhook_module . HookEventDelete :
2024-03-07 23:18:38 +01:00
return convertUnmarshalledJSON ( rc . Delete , data )
2023-01-01 16:23:15 +01:00
case webhook_module . HookEventFork :
2024-03-07 23:18:38 +01:00
return convertUnmarshalledJSON ( rc . Fork , data )
2023-01-01 16:23:15 +01:00
case webhook_module . HookEventIssues , webhook_module . HookEventIssueAssign , webhook_module . HookEventIssueLabel , webhook_module . HookEventIssueMilestone :
2024-03-07 23:18:38 +01:00
return convertUnmarshalledJSON ( rc . Issue , data )
2023-01-01 16:23:15 +01:00
case webhook_module . HookEventIssueComment , webhook_module . HookEventPullRequestComment :
2024-03-07 23:18:38 +01:00
// previous code sometimes sent s.PullRequest(p.(*api.PullRequestPayload))
// however I couldn't find in notifier.go such a payload with an HookEvent***Comment event
// History (most recent first):
// - refactored in https://github.com/go-gitea/gitea/pull/12310
// - assertion added in https://github.com/go-gitea/gitea/pull/12046
// - issue raised in https://github.com/go-gitea/gitea/issues/11940#issuecomment-645713996
// > That's because for HookEventPullRequestComment event, some places use IssueCommentPayload and others use PullRequestPayload
// In modules/actions/workflows.go:183 the type assertion is always payload.(*api.IssueCommentPayload)
return convertUnmarshalledJSON ( rc . IssueComment , data )
2023-01-01 16:23:15 +01:00
case webhook_module . HookEventPush :
2024-03-07 23:18:38 +01:00
return convertUnmarshalledJSON ( rc . Push , data )
2023-01-01 16:23:15 +01:00
case webhook_module . HookEventPullRequest , webhook_module . HookEventPullRequestAssign , webhook_module . HookEventPullRequestLabel ,
2023-05-25 10:06:27 +08:00
webhook_module . HookEventPullRequestMilestone , webhook_module . HookEventPullRequestSync , webhook_module . HookEventPullRequestReviewRequest :
2024-03-07 23:18:38 +01:00
return convertUnmarshalledJSON ( rc . PullRequest , data )
2023-01-01 16:23:15 +01:00
case webhook_module . HookEventPullRequestReviewApproved , webhook_module . HookEventPullRequestReviewRejected , webhook_module . HookEventPullRequestReviewComment :
2024-03-07 23:18:38 +01:00
return convertUnmarshalledJSON ( func ( p * api . PullRequestPayload ) ( T , error ) {
return rc . Review ( p , event )
} , data )
2023-01-01 16:23:15 +01:00
case webhook_module . HookEventRepository :
2024-03-07 23:18:38 +01:00
return convertUnmarshalledJSON ( rc . Repository , data )
2023-01-01 16:23:15 +01:00
case webhook_module . HookEventRelease :
2024-03-07 23:18:38 +01:00
return convertUnmarshalledJSON ( rc . Release , data )
2023-01-01 16:23:15 +01:00
case webhook_module . HookEventWiki :
2024-03-07 23:18:38 +01:00
return convertUnmarshalledJSON ( rc . Wiki , data )
2023-10-31 12:43:38 +08:00
case webhook_module . HookEventPackage :
2024-03-07 23:18:38 +01:00
return convertUnmarshalledJSON ( rc . Package , data )
}
var t T
return t , fmt . Errorf ( "newPayload unsupported event: %s" , event )
}
func newJSONRequest [ T any ] ( pc payloadConvertor [ T ] , w * webhook_model . Webhook , t * webhook_model . HookTask , withDefaultHeaders bool ) ( * http . Request , [ ] byte , error ) {
payload , err := newPayload ( pc , [ ] byte ( t . PayloadContent ) , t . EventType )
if err != nil {
return nil , nil , err
}
body , err := json . MarshalIndent ( payload , "" , " " )
if err != nil {
return nil , nil , err
}
2024-03-10 09:32:48 +08:00
method := w . HTTPMethod
if method == "" {
method = http . MethodPost
}
req , err := http . NewRequest ( method , w . URL , bytes . NewReader ( body ) )
2024-03-07 23:18:38 +01:00
if err != nil {
return nil , nil , err
}
req . Header . Set ( "Content-Type" , "application/json" )
if withDefaultHeaders {
return req , body , addDefaultHeaders ( req , [ ] byte ( w . Secret ) , t , body )
2020-09-05 10:57:13 +08:00
}
2024-03-07 23:18:38 +01:00
return req , body , nil
2020-09-05 10:57:13 +08:00
}