2019-04-19 17:18:06 +03:00
// Copyright 2019 The Gitea Authors. All rights reserved.
2022-11-27 21:20:29 +03:00
// SPDX-License-Identifier: MIT
2019-04-19 17:18:06 +03:00
2019-11-04 01:13:25 +03:00
package webhook
2019-04-19 17:18:06 +03:00
import (
2024-03-08 01:18:38 +03:00
"context"
2019-04-19 17:18:06 +03:00
"fmt"
2024-03-08 01:18:38 +03:00
"net/http"
2022-09-04 22:54:23 +03:00
"net/url"
2019-04-19 17:18:06 +03:00
"strings"
2024-03-08 01:18:38 +03:00
webhook_model "code.gitea.io/gitea/models/webhook"
2019-04-19 17:18:06 +03:00
"code.gitea.io/gitea/modules/git"
2019-05-11 13:21:34 +03:00
api "code.gitea.io/gitea/modules/structs"
2021-11-16 21:18:25 +03:00
"code.gitea.io/gitea/modules/util"
2023-01-01 18:23:15 +03:00
webhook_module "code.gitea.io/gitea/modules/webhook"
2019-04-19 17:18:06 +03:00
)
2024-03-20 17:44:01 +03:00
type msteamsHandler struct { }
func ( msteamsHandler ) Type ( ) webhook_module . HookType { return webhook_module . MSTEAMS }
func ( msteamsHandler ) Metadata ( * webhook_model . Webhook ) any { return nil }
2024-03-21 15:23:27 +03:00
func ( msteamsHandler ) FormFields ( bind func ( any ) ) FormFields {
panic ( "TODO" )
}
2019-04-19 17:18:06 +03:00
type (
// MSTeamsFact for Fact Structure
MSTeamsFact struct {
Name string ` json:"name" `
Value string ` json:"value" `
}
// MSTeamsSection is a MessageCard section
MSTeamsSection struct {
ActivityTitle string ` json:"activityTitle" `
ActivitySubtitle string ` json:"activitySubtitle" `
ActivityImage string ` json:"activityImage" `
Facts [ ] MSTeamsFact ` json:"facts" `
Text string ` json:"text" `
}
// MSTeamsAction is an action (creates buttons, links etc)
MSTeamsAction struct {
Type string ` json:"@type" `
Name string ` json:"name" `
Targets [ ] MSTeamsActionTarget ` json:"targets,omitempty" `
}
// MSTeamsActionTarget is the actual link to follow, etc
MSTeamsActionTarget struct {
Os string ` json:"os" `
URI string ` json:"uri" `
}
// MSTeamsPayload is the parent object
MSTeamsPayload struct {
Type string ` json:"@type" `
Context string ` json:"@context" `
ThemeColor string ` json:"themeColor" `
Title string ` json:"title" `
Summary string ` json:"summary" `
Sections [ ] MSTeamsSection ` json:"sections" `
PotentialAction [ ] MSTeamsAction ` json:"potentialAction" `
}
)
2020-09-05 05:57:13 +03:00
// Create implements PayloadConvertor Create method
2024-03-08 01:18:38 +03:00
func ( m msteamsConvertor ) Create ( p * api . CreatePayload ) ( MSTeamsPayload , error ) {
2019-04-19 17:18:06 +03:00
// created tag/branch
2023-05-26 04:04:48 +03:00
refName := git . RefName ( p . Ref ) . ShortName ( )
2019-04-19 17:18:06 +03:00
title := fmt . Sprintf ( "[%s] %s %s created" , p . Repo . FullName , p . RefType , refName )
2021-06-21 05:12:19 +03:00
return createMSTeamsPayload (
p . Repo ,
p . Sender ,
title ,
"" ,
2021-11-16 21:18:25 +03:00
p . Repo . HTMLURL + "/src/" + util . PathEscapeSegments ( refName ) ,
2021-06-21 05:12:19 +03:00
greenColor ,
& MSTeamsFact { fmt . Sprintf ( "%s:" , p . RefType ) , refName } ,
) , nil
2019-04-19 17:18:06 +03:00
}
2020-09-05 05:57:13 +03:00
// Delete implements PayloadConvertor Delete method
2024-03-08 01:18:38 +03:00
func ( m msteamsConvertor ) Delete ( p * api . DeletePayload ) ( MSTeamsPayload , error ) {
2019-04-19 17:18:06 +03:00
// deleted tag/branch
2023-05-26 04:04:48 +03:00
refName := git . RefName ( p . Ref ) . ShortName ( )
2019-04-19 17:18:06 +03:00
title := fmt . Sprintf ( "[%s] %s %s deleted" , p . Repo . FullName , p . RefType , refName )
2021-06-21 05:12:19 +03:00
return createMSTeamsPayload (
p . Repo ,
p . Sender ,
title ,
"" ,
2021-11-16 21:18:25 +03:00
p . Repo . HTMLURL + "/src/" + util . PathEscapeSegments ( refName ) ,
2021-06-21 05:12:19 +03:00
yellowColor ,
& MSTeamsFact { fmt . Sprintf ( "%s:" , p . RefType ) , refName } ,
) , nil
2019-04-19 17:18:06 +03:00
}
2020-09-05 05:57:13 +03:00
// Fork implements PayloadConvertor Fork method
2024-03-08 01:18:38 +03:00
func ( m msteamsConvertor ) Fork ( p * api . ForkPayload ) ( MSTeamsPayload , error ) {
2019-04-19 17:18:06 +03:00
title := fmt . Sprintf ( "%s is forked to %s" , p . Forkee . FullName , p . Repo . FullName )
2021-06-21 05:12:19 +03:00
return createMSTeamsPayload (
p . Repo ,
p . Sender ,
title ,
"" ,
p . Repo . HTMLURL ,
greenColor ,
& MSTeamsFact { "Forkee:" , p . Forkee . FullName } ,
) , nil
2019-04-19 17:18:06 +03:00
}
2020-09-05 05:57:13 +03:00
// Push implements PayloadConvertor Push method
2024-03-08 01:18:38 +03:00
func ( m msteamsConvertor ) Push ( p * api . PushPayload ) ( MSTeamsPayload , error ) {
2019-04-19 17:18:06 +03:00
var (
2023-05-26 04:04:48 +03:00
branchName = git . RefName ( p . Ref ) . ShortName ( )
2019-04-19 17:18:06 +03:00
commitDesc string
)
var titleLink string
2022-10-16 19:22:34 +03:00
if p . TotalCommits == 1 {
2019-04-19 17:18:06 +03:00
commitDesc = "1 new commit"
titleLink = p . Commits [ 0 ] . URL
} else {
2022-10-16 19:22:34 +03:00
commitDesc = fmt . Sprintf ( "%d new commits" , p . TotalCommits )
2019-04-19 17:18:06 +03:00
titleLink = p . CompareURL
}
if titleLink == "" {
2021-11-16 21:18:25 +03:00
titleLink = p . Repo . HTMLURL + "/src/" + util . PathEscapeSegments ( branchName )
2019-04-19 17:18:06 +03:00
}
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 {
text += fmt . Sprintf ( "[%s](%s) %s - %s" , commit . ID [ : 7 ] , commit . URL ,
strings . TrimRight ( commit . Message , "\r\n" ) , commit . Author . Name )
// add linebreak to each commit but the last
if i < len ( p . Commits ) - 1 {
2020-10-09 08:30:55 +03:00
text += "\n\n"
2019-04-19 17:18:06 +03:00
}
}
2021-06-21 05:12:19 +03:00
return createMSTeamsPayload (
p . Repo ,
p . Sender ,
title ,
text ,
titleLink ,
greenColor ,
2022-10-16 19:22:34 +03:00
& MSTeamsFact { "Commit count:" , fmt . Sprintf ( "%d" , p . TotalCommits ) } ,
2021-06-21 05:12:19 +03:00
) , nil
2019-04-19 17:18:06 +03:00
}
2020-09-05 05:57:13 +03:00
// Issue implements PayloadConvertor Issue method
2024-03-08 01:18:38 +03:00
func ( m msteamsConvertor ) Issue ( p * api . IssuePayload ) ( MSTeamsPayload , error ) {
2021-06-21 05:12:19 +03:00
title , _ , attachmentText , color := getIssuesPayloadInfo ( p , noneLinkFormatter , false )
return createMSTeamsPayload (
p . Repository ,
p . Sender ,
title ,
attachmentText ,
p . Issue . HTMLURL ,
color ,
& MSTeamsFact { "Issue #:" , fmt . Sprintf ( "%d" , p . Issue . ID ) } ,
) , nil
2019-04-19 17:18:06 +03:00
}
2020-09-05 05:57:13 +03:00
// IssueComment implements PayloadConvertor IssueComment method
2024-03-08 01:18:38 +03:00
func ( m msteamsConvertor ) IssueComment ( p * api . IssueCommentPayload ) ( MSTeamsPayload , error ) {
2021-06-21 05:12:19 +03:00
title , _ , color := getIssueCommentPayloadInfo ( p , noneLinkFormatter , false )
return createMSTeamsPayload (
p . Repository ,
p . Sender ,
title ,
p . Comment . Body ,
p . Comment . HTMLURL ,
color ,
& MSTeamsFact { "Issue #:" , fmt . Sprintf ( "%d" , p . Issue . ID ) } ,
) , nil
2019-04-19 17:18:06 +03:00
}
2020-09-05 05:57:13 +03:00
// PullRequest implements PayloadConvertor PullRequest method
2024-03-08 01:18:38 +03:00
func ( m msteamsConvertor ) PullRequest ( p * api . PullRequestPayload ) ( MSTeamsPayload , error ) {
2021-06-21 05:12:19 +03:00
title , _ , attachmentText , color := getPullRequestPayloadInfo ( p , noneLinkFormatter , false )
return createMSTeamsPayload (
p . Repository ,
p . Sender ,
title ,
attachmentText ,
p . PullRequest . HTMLURL ,
color ,
& MSTeamsFact { "Pull request #:" , fmt . Sprintf ( "%d" , p . PullRequest . ID ) } ,
) , nil
2019-04-19 17:18:06 +03:00
}
2020-09-05 05:57:13 +03:00
// Review implements PayloadConvertor Review method
2024-03-08 01:18:38 +03:00
func ( m msteamsConvertor ) Review ( p * api . PullRequestPayload , event webhook_module . HookEventType ) ( MSTeamsPayload , error ) {
2019-04-19 17:18:06 +03:00
var text , title string
var color int
switch p . Action {
2020-03-06 08:10:48 +03:00
case api . HookIssueReviewed :
2019-04-19 17:18:06 +03:00
action , err := parseHookPullRequestEventType ( event )
if err != nil {
2024-03-08 01:18:38 +03:00
return MSTeamsPayload { } , err
2019-04-19 17:18:06 +03:00
}
title = fmt . Sprintf ( "[%s] Pull request review %s: #%d %s" , p . Repository . FullName , action , p . Index , p . PullRequest . Title )
2019-10-19 01:42:04 +03:00
text = p . Review . Content
switch event {
2023-01-01 18:23:15 +03:00
case webhook_module . HookEventPullRequestReviewApproved :
2019-10-19 01:42:04 +03:00
color = greenColor
2023-01-01 18:23:15 +03:00
case webhook_module . HookEventPullRequestReviewRejected :
2019-10-19 01:42:04 +03:00
color = redColor
2023-03-24 08:13:04 +03:00
case webhook_module . HookEventPullRequestReviewComment :
2019-10-19 01:42:04 +03:00
color = greyColor
default :
color = yellowColor
}
2019-04-19 17:18:06 +03:00
}
2021-06-21 05:12:19 +03:00
return createMSTeamsPayload (
p . Repository ,
p . Sender ,
title ,
text ,
p . PullRequest . HTMLURL ,
color ,
& MSTeamsFact { "Pull request #:" , fmt . Sprintf ( "%d" , p . PullRequest . ID ) } ,
) , nil
2019-04-19 17:18:06 +03:00
}
2020-09-05 05:57:13 +03:00
// Repository implements PayloadConvertor Repository method
2024-03-08 01:18:38 +03:00
func ( m msteamsConvertor ) Repository ( p * api . RepositoryPayload ) ( MSTeamsPayload , error ) {
2019-04-19 17:18:06 +03:00
var title , url string
var color int
switch p . Action {
case api . HookRepoCreated :
title = fmt . Sprintf ( "[%s] Repository created" , p . Repository . FullName )
url = p . Repository . HTMLURL
2019-10-19 01:42:04 +03:00
color = greenColor
2019-04-19 17:18:06 +03:00
case api . HookRepoDeleted :
title = fmt . Sprintf ( "[%s] Repository deleted" , p . Repository . FullName )
2019-10-19 01:42:04 +03:00
color = yellowColor
2019-04-19 17:18:06 +03:00
}
2021-06-21 05:12:19 +03:00
return createMSTeamsPayload (
p . Repository ,
p . Sender ,
title ,
"" ,
url ,
color ,
nil ,
) , nil
2019-04-19 17:18:06 +03:00
}
2022-09-04 22:54:23 +03:00
// Wiki implements PayloadConvertor Wiki method
2024-03-08 01:18:38 +03:00
func ( m msteamsConvertor ) Wiki ( p * api . WikiPayload ) ( MSTeamsPayload , error ) {
2022-09-04 22:54:23 +03:00
title , color , _ := getWikiPayloadInfo ( p , noneLinkFormatter , false )
return createMSTeamsPayload (
p . Repository ,
p . Sender ,
title ,
"" ,
p . Repository . HTMLURL + "/wiki/" + url . PathEscape ( p . Page ) ,
color ,
& MSTeamsFact { "Repository:" , p . Repository . FullName } ,
) , nil
}
2020-09-05 05:57:13 +03:00
// Release implements PayloadConvertor Release method
2024-03-08 01:18:38 +03:00
func ( m msteamsConvertor ) Release ( p * api . ReleasePayload ) ( MSTeamsPayload , error ) {
2021-06-21 05:12:19 +03:00
title , color := getReleasePayloadInfo ( p , noneLinkFormatter , false )
return createMSTeamsPayload (
p . Repository ,
p . Sender ,
title ,
"" ,
2023-09-22 01:55:09 +03:00
p . Release . HTMLURL ,
2021-06-21 05:12:19 +03:00
color ,
& MSTeamsFact { "Tag:" , p . Release . TagName } ,
) , nil
}
2024-03-08 01:18:38 +03:00
func ( m msteamsConvertor ) Package ( p * api . PackagePayload ) ( MSTeamsPayload , error ) {
2023-10-31 07:43:38 +03:00
title , color := getPackagePayloadInfo ( p , noneLinkFormatter , false )
return createMSTeamsPayload (
p . Repository ,
p . Sender ,
title ,
"" ,
p . Package . HTMLURL ,
color ,
& MSTeamsFact { "Package:" , p . Package . Name } ,
) , nil
}
2024-03-08 01:18:38 +03:00
func createMSTeamsPayload ( r * api . Repository , s * api . User , title , text , actionTarget string , color int , fact * MSTeamsFact ) MSTeamsPayload {
2023-11-17 14:17:33 +03:00
facts := make ( [ ] MSTeamsFact , 0 , 2 )
if r != nil {
facts = append ( facts , MSTeamsFact {
2021-06-21 05:12:19 +03:00
Name : "Repository:" ,
Value : r . FullName ,
2023-11-17 14:17:33 +03:00
} )
2021-06-21 05:12:19 +03:00
}
if fact != nil {
facts = append ( facts , * fact )
}
2019-04-19 17:18:06 +03:00
2024-03-08 01:18:38 +03:00
return MSTeamsPayload {
2019-04-19 17:18:06 +03:00
Type : "MessageCard" ,
Context : "https://schema.org/extensions" ,
ThemeColor : fmt . Sprintf ( "%x" , color ) ,
2021-06-21 05:12:19 +03:00
Title : title ,
Summary : title ,
2019-04-19 17:18:06 +03:00
Sections : [ ] MSTeamsSection {
{
2021-06-21 05:12:19 +03:00
ActivityTitle : s . FullName ,
ActivitySubtitle : s . UserName ,
ActivityImage : s . AvatarURL ,
Text : text ,
Facts : facts ,
2019-04-19 17:18:06 +03:00
} ,
} ,
PotentialAction : [ ] MSTeamsAction {
{
Type : "OpenUri" ,
Name : "View in Gitea" ,
Targets : [ ] MSTeamsActionTarget {
{
Os : "default" ,
2021-06-21 05:12:19 +03:00
URI : actionTarget ,
2019-04-19 17:18:06 +03:00
} ,
} ,
} ,
} ,
2021-06-21 05:12:19 +03:00
}
2019-04-19 17:18:06 +03:00
}
2024-03-08 01:18:38 +03:00
type msteamsConvertor struct { }
var _ payloadConvertor [ MSTeamsPayload ] = msteamsConvertor { }
2024-03-20 17:44:01 +03:00
func ( msteamsHandler ) NewRequest ( ctx context . Context , w * webhook_model . Webhook , t * webhook_model . HookTask ) ( * http . Request , [ ] byte , error ) {
2024-03-08 01:18:38 +03:00
return newJSONRequest ( msteamsConvertor { } , w , t , true )
}