1// Copyright 2020 The Gitea Authors. All rights reserved.
2// Use of this source code is governed by a MIT-style
3// license that can be found in the LICENSE file.
4
5package webhook
6
7import (
8	"fmt"
9	"strings"
10
11	webhook_model "code.gitea.io/gitea/models/webhook"
12	"code.gitea.io/gitea/modules/git"
13	"code.gitea.io/gitea/modules/json"
14	api "code.gitea.io/gitea/modules/structs"
15)
16
17type (
18	// FeishuPayload represents
19	FeishuPayload struct {
20		MsgType string `json:"msg_type"` // text / post / image / share_chat / interactive
21		Content struct {
22			Text string `json:"text"`
23		} `json:"content"`
24	}
25)
26
27func newFeishuTextPayload(text string) *FeishuPayload {
28	return &FeishuPayload{
29		MsgType: "text",
30		Content: struct {
31			Text string `json:"text"`
32		}{
33			Text: strings.TrimSpace(text),
34		},
35	}
36}
37
38// JSONPayload Marshals the FeishuPayload to json
39func (f *FeishuPayload) JSONPayload() ([]byte, error) {
40	data, err := json.MarshalIndent(f, "", "  ")
41	if err != nil {
42		return []byte{}, err
43	}
44	return data, nil
45}
46
47var (
48	_ PayloadConvertor = &FeishuPayload{}
49)
50
51// Create implements PayloadConvertor Create method
52func (f *FeishuPayload) Create(p *api.CreatePayload) (api.Payloader, error) {
53	// created tag/branch
54	refName := git.RefEndName(p.Ref)
55	text := fmt.Sprintf("[%s] %s %s created", p.Repo.FullName, p.RefType, refName)
56
57	return newFeishuTextPayload(text), nil
58}
59
60// Delete implements PayloadConvertor Delete method
61func (f *FeishuPayload) Delete(p *api.DeletePayload) (api.Payloader, error) {
62	// created tag/branch
63	refName := git.RefEndName(p.Ref)
64	text := fmt.Sprintf("[%s] %s %s deleted", p.Repo.FullName, p.RefType, refName)
65
66	return newFeishuTextPayload(text), nil
67}
68
69// Fork implements PayloadConvertor Fork method
70func (f *FeishuPayload) Fork(p *api.ForkPayload) (api.Payloader, error) {
71	text := fmt.Sprintf("%s is forked to %s", p.Forkee.FullName, p.Repo.FullName)
72
73	return newFeishuTextPayload(text), nil
74}
75
76// Push implements PayloadConvertor Push method
77func (f *FeishuPayload) Push(p *api.PushPayload) (api.Payloader, error) {
78	var (
79		branchName = git.RefEndName(p.Ref)
80		commitDesc string
81	)
82
83	var text = fmt.Sprintf("[%s:%s] %s\r\n", p.Repo.FullName, branchName, commitDesc)
84	// for each commit, generate attachment text
85	for i, commit := range p.Commits {
86		var authorName string
87		if commit.Author != nil {
88			authorName = " - " + commit.Author.Name
89		}
90		text += fmt.Sprintf("[%s](%s) %s", commit.ID[:7], commit.URL,
91			strings.TrimRight(commit.Message, "\r\n")) + authorName
92		// add linebreak to each commit but the last
93		if i < len(p.Commits)-1 {
94			text += "\r\n"
95		}
96	}
97
98	return newFeishuTextPayload(text), nil
99}
100
101// Issue implements PayloadConvertor Issue method
102func (f *FeishuPayload) Issue(p *api.IssuePayload) (api.Payloader, error) {
103	text, issueTitle, attachmentText, _ := getIssuesPayloadInfo(p, noneLinkFormatter, true)
104
105	return newFeishuTextPayload(issueTitle + "\r\n" + text + "\r\n\r\n" + attachmentText), nil
106}
107
108// IssueComment implements PayloadConvertor IssueComment method
109func (f *FeishuPayload) IssueComment(p *api.IssueCommentPayload) (api.Payloader, error) {
110	text, issueTitle, _ := getIssueCommentPayloadInfo(p, noneLinkFormatter, true)
111
112	return newFeishuTextPayload(issueTitle + "\r\n" + text + "\r\n\r\n" + p.Comment.Body), nil
113}
114
115// PullRequest implements PayloadConvertor PullRequest method
116func (f *FeishuPayload) PullRequest(p *api.PullRequestPayload) (api.Payloader, error) {
117	text, issueTitle, attachmentText, _ := getPullRequestPayloadInfo(p, noneLinkFormatter, true)
118
119	return newFeishuTextPayload(issueTitle + "\r\n" + text + "\r\n\r\n" + attachmentText), nil
120}
121
122// Review implements PayloadConvertor Review method
123func (f *FeishuPayload) Review(p *api.PullRequestPayload, event webhook_model.HookEventType) (api.Payloader, error) {
124	action, err := parseHookPullRequestEventType(event)
125	if err != nil {
126		return nil, err
127	}
128
129	title := fmt.Sprintf("[%s] Pull request review %s : #%d %s", p.Repository.FullName, action, p.Index, p.PullRequest.Title)
130	text := p.Review.Content
131
132	return newFeishuTextPayload(title + "\r\n\r\n" + text), nil
133}
134
135// Repository implements PayloadConvertor Repository method
136func (f *FeishuPayload) Repository(p *api.RepositoryPayload) (api.Payloader, error) {
137	var text string
138	switch p.Action {
139	case api.HookRepoCreated:
140		text = fmt.Sprintf("[%s] Repository created", p.Repository.FullName)
141		return newFeishuTextPayload(text), nil
142	case api.HookRepoDeleted:
143		text = fmt.Sprintf("[%s] Repository deleted", p.Repository.FullName)
144		return newFeishuTextPayload(text), nil
145	}
146
147	return nil, nil
148}
149
150// Release implements PayloadConvertor Release method
151func (f *FeishuPayload) Release(p *api.ReleasePayload) (api.Payloader, error) {
152	text, _ := getReleasePayloadInfo(p, noneLinkFormatter, true)
153
154	return newFeishuTextPayload(text), nil
155}
156
157// GetFeishuPayload converts a ding talk webhook into a FeishuPayload
158func GetFeishuPayload(p api.Payloader, event webhook_model.HookEventType, meta string) (api.Payloader, error) {
159	return convertPayloader(new(FeishuPayload), p, event)
160}
161