2017-11-20 23:26:43 -05:00
// Copyright 2017 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
2019-11-03 17:13:25 -05:00
package webhook
2017-11-20 23:26:43 -05:00
import (
"fmt"
2021-09-18 15:35:23 -04:00
"net/url"
2017-11-20 23:26:43 -05:00
"strings"
2019-11-03 17:13:25 -05:00
"code.gitea.io/gitea/models"
2019-03-27 05:33:00 -04:00
"code.gitea.io/gitea/modules/git"
2021-07-24 12:03:58 -04:00
"code.gitea.io/gitea/modules/json"
2019-05-11 06:21:34 -04:00
api "code.gitea.io/gitea/modules/structs"
2019-03-27 05:33:00 -04:00
2017-11-20 23:26:43 -05:00
dingtalk "github.com/lunny/dingtalk_webhook"
)
type (
// DingtalkPayload represents
DingtalkPayload dingtalk . Payload
)
2020-09-04 22:57:13 -04:00
var (
_ PayloadConvertor = & DingtalkPayload { }
)
2017-11-20 23:26:43 -05:00
// JSONPayload Marshals the DingtalkPayload to json
2020-09-04 22:57:13 -04:00
func ( d * DingtalkPayload ) JSONPayload ( ) ( [ ] byte , error ) {
data , err := json . MarshalIndent ( d , "" , " " )
2017-11-20 23:26:43 -05:00
if err != nil {
return [ ] byte { } , err
}
return data , nil
}
2020-09-04 22:57:13 -04:00
// Create implements PayloadConvertor Create method
func ( d * DingtalkPayload ) Create ( p * api . CreatePayload ) ( api . Payloader , error ) {
2017-11-20 23:26:43 -05:00
// created tag/branch
refName := git . RefEndName ( p . Ref )
title := fmt . Sprintf ( "[%s] %s %s created" , p . Repo . FullName , p . RefType , refName )
2021-06-20 22:12:19 -04:00
return createDingtalkPayload ( title , title , fmt . Sprintf ( "view ref %s" , refName ) , p . Repo . HTMLURL + "/src/" + refName ) , nil
2017-11-20 23:26:43 -05:00
}
2020-09-04 22:57:13 -04:00
// Delete implements PayloadConvertor Delete method
func ( d * DingtalkPayload ) Delete ( p * api . DeletePayload ) ( api . Payloader , error ) {
2018-05-16 10:01:55 -04:00
// created tag/branch
refName := git . RefEndName ( p . Ref )
title := fmt . Sprintf ( "[%s] %s %s deleted" , p . Repo . FullName , p . RefType , refName )
2021-06-20 22:12:19 -04:00
return createDingtalkPayload ( title , title , fmt . Sprintf ( "view ref %s" , refName ) , p . Repo . HTMLURL + "/src/" + refName ) , nil
2018-05-16 10:01:55 -04:00
}
2020-09-04 22:57:13 -04:00
// Fork implements PayloadConvertor Fork method
func ( d * DingtalkPayload ) Fork ( p * api . ForkPayload ) ( api . Payloader , error ) {
2018-05-16 10:01:55 -04:00
title := fmt . Sprintf ( "%s is forked to %s" , p . Forkee . FullName , p . Repo . FullName )
2021-06-20 22:12:19 -04:00
return createDingtalkPayload ( title , title , fmt . Sprintf ( "view forked repo %s" , p . Repo . FullName ) , p . Repo . HTMLURL ) , nil
2018-05-16 10:01:55 -04:00
}
2020-09-04 22:57:13 -04:00
// Push implements PayloadConvertor Push method
func ( d * DingtalkPayload ) Push ( p * api . PushPayload ) ( api . Payloader , error ) {
2017-11-20 23:26:43 -05:00
var (
branchName = git . RefEndName ( p . Ref )
commitDesc string
)
var titleLink , linkText string
if len ( p . Commits ) == 1 {
commitDesc = "1 new commit"
titleLink = p . Commits [ 0 ] . URL
linkText = fmt . Sprintf ( "view commit %s" , p . Commits [ 0 ] . ID [ : 7 ] )
} else {
commitDesc = fmt . Sprintf ( "%d new commits" , len ( p . Commits ) )
titleLink = p . CompareURL
linkText = fmt . Sprintf ( "view commit %s...%s" , p . Commits [ 0 ] . ID [ : 7 ] , p . Commits [ len ( p . Commits ) - 1 ] . ID [ : 7 ] )
}
if titleLink == "" {
titleLink = p . Repo . HTMLURL + "/src/" + branchName
}
title := fmt . Sprintf ( "[%s:%s] %s" , p . Repo . FullName , branchName , commitDesc )
var text string
// for each commit, generate attachment text
for i , commit := range p . Commits {
var authorName string
if commit . Author != nil {
authorName = " - " + commit . Author . Name
}
text += fmt . Sprintf ( "[%s](%s) %s" , commit . ID [ : 7 ] , commit . URL ,
strings . TrimRight ( commit . Message , "\r\n" ) ) + authorName
// add linebreak to each commit but the last
if i < len ( p . Commits ) - 1 {
2021-06-20 22:12:19 -04:00
text += "\r\n"
2017-11-20 23:26:43 -05:00
}
}
2021-06-20 22:12:19 -04:00
return createDingtalkPayload ( title , text , linkText , titleLink ) , nil
2017-11-20 23:26:43 -05:00
}
2020-09-04 22:57:13 -04:00
// Issue implements PayloadConvertor Issue method
func ( d * DingtalkPayload ) Issue ( p * api . IssuePayload ) ( api . Payloader , error ) {
2020-01-04 17:20:15 -05:00
text , issueTitle , attachmentText , _ := getIssuesPayloadInfo ( p , noneLinkFormatter , true )
2018-05-16 10:01:55 -04:00
2021-06-20 22:12:19 -04:00
return createDingtalkPayload ( issueTitle , text + "\r\n\r\n" + attachmentText , "view issue" , p . Issue . HTMLURL ) , nil
2018-05-16 10:01:55 -04:00
}
2020-09-04 22:57:13 -04:00
// IssueComment implements PayloadConvertor IssueComment method
func ( d * DingtalkPayload ) IssueComment ( p * api . IssueCommentPayload ) ( api . Payloader , error ) {
2020-01-04 17:20:15 -05:00
text , issueTitle , _ := getIssueCommentPayloadInfo ( p , noneLinkFormatter , true )
2019-10-18 18:42:04 -04:00
2021-06-20 22:12:19 -04:00
return createDingtalkPayload ( issueTitle , text + "\r\n\r\n" + p . Comment . Body , "view issue comment" , p . Comment . HTMLURL ) , nil
2018-05-16 10:01:55 -04:00
}
2020-09-04 22:57:13 -04:00
// PullRequest implements PayloadConvertor PullRequest method
func ( d * DingtalkPayload ) PullRequest ( p * api . PullRequestPayload ) ( api . Payloader , error ) {
2020-01-04 17:20:15 -05:00
text , issueTitle , attachmentText , _ := getPullRequestPayloadInfo ( p , noneLinkFormatter , true )
2017-11-20 23:26:43 -05:00
2021-06-20 22:12:19 -04:00
return createDingtalkPayload ( issueTitle , text + "\r\n\r\n" + attachmentText , "view pull request" , p . PullRequest . HTMLURL ) , nil
2017-11-20 23:26:43 -05:00
}
2020-09-04 22:57:13 -04:00
// Review implements PayloadConvertor Review method
func ( d * DingtalkPayload ) Review ( p * api . PullRequestPayload , event models . HookEventType ) ( api . Payloader , error ) {
2018-12-27 13:04:30 -05:00
var text , title string
switch p . Action {
2020-03-06 00:10:48 -05:00
case api . HookIssueReviewed :
2018-12-27 13:04:30 -05:00
action , err := parseHookPullRequestEventType ( event )
if err != nil {
return nil , err
}
title = fmt . Sprintf ( "[%s] Pull request review %s : #%d %s" , p . Repository . FullName , action , p . Index , p . PullRequest . Title )
2019-10-18 18:42:04 -04:00
text = p . Review . Content
2018-12-27 13:04:30 -05:00
}
2021-06-20 22:12:19 -04:00
return createDingtalkPayload ( title , title + "\r\n\r\n" + text , "view pull request" , p . PullRequest . HTMLURL ) , nil
2018-12-27 13:04:30 -05:00
}
2020-09-04 22:57:13 -04:00
// Repository implements PayloadConvertor Repository method
func ( d * DingtalkPayload ) Repository ( p * api . RepositoryPayload ) ( api . Payloader , error ) {
2017-11-20 23:26:43 -05:00
switch p . Action {
case api . HookRepoCreated :
2021-06-20 22:12:19 -04:00
title := fmt . Sprintf ( "[%s] Repository created" , p . Repository . FullName )
return createDingtalkPayload ( title , title , "view repository" , p . Repository . HTMLURL ) , nil
2017-11-20 23:26:43 -05:00
case api . HookRepoDeleted :
2021-06-20 22:12:19 -04:00
title := fmt . Sprintf ( "[%s] Repository deleted" , p . Repository . FullName )
2017-11-20 23:26:43 -05:00
return & DingtalkPayload {
MsgType : "text" ,
Text : struct {
Content string ` json:"content" `
} {
Content : title ,
} ,
} , nil
}
return nil , nil
}
2020-09-04 22:57:13 -04:00
// Release implements PayloadConvertor Release method
func ( d * DingtalkPayload ) Release ( p * api . ReleasePayload ) ( api . Payloader , error ) {
2020-01-04 17:20:15 -05:00
text , _ := getReleasePayloadInfo ( p , noneLinkFormatter , true )
2018-05-20 22:28:29 -04:00
2021-06-20 22:12:19 -04:00
return createDingtalkPayload ( text , text , "view release" , p . Release . URL ) , nil
}
func createDingtalkPayload ( title , text , singleTitle , singleURL string ) * DingtalkPayload {
2019-12-28 03:55:09 -05:00
return & DingtalkPayload {
MsgType : "actionCard" ,
ActionCard : dingtalk . ActionCard {
2021-06-20 22:12:19 -04:00
Text : strings . TrimSpace ( text ) ,
Title : strings . TrimSpace ( title ) ,
2019-12-28 03:55:09 -05:00
HideAvatar : "0" ,
2021-06-20 22:12:19 -04:00
SingleTitle : singleTitle ,
2021-09-18 15:35:23 -04:00
// https://developers.dingtalk.com/document/app/message-link-description
// to open the link in browser, we should use this URL, otherwise the page is displayed inside DingTalk client, very difficult to visit non-public URLs.
SingleURL : "dingtalk://dingtalkclient/page/link?pc_slide=false&url=" + url . QueryEscape ( singleURL ) ,
2019-12-28 03:55:09 -05:00
} ,
2021-06-20 22:12:19 -04:00
}
2018-05-16 10:01:55 -04:00
}
2017-11-20 23:26:43 -05:00
// GetDingtalkPayload converts a ding talk webhook into a DingtalkPayload
2020-09-04 22:57:13 -04:00
func GetDingtalkPayload ( p api . Payloader , event models . HookEventType , meta string ) ( api . Payloader , error ) {
return convertPayloader ( new ( DingtalkPayload ) , p , event )
2017-11-20 23:26:43 -05:00
}