gitea源码

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. // Copyright 2019 The Gitea Authors. All rights reserved.
  2. // SPDX-License-Identifier: MIT
  3. package webhook
  4. import (
  5. "context"
  6. "fmt"
  7. "html"
  8. "net/http"
  9. "strings"
  10. webhook_model "code.gitea.io/gitea/models/webhook"
  11. "code.gitea.io/gitea/modules/git"
  12. "code.gitea.io/gitea/modules/json"
  13. "code.gitea.io/gitea/modules/log"
  14. "code.gitea.io/gitea/modules/markup"
  15. api "code.gitea.io/gitea/modules/structs"
  16. "code.gitea.io/gitea/modules/util"
  17. webhook_module "code.gitea.io/gitea/modules/webhook"
  18. )
  19. type (
  20. // TelegramPayload represents
  21. TelegramPayload struct {
  22. Message string `json:"text"`
  23. ParseMode string `json:"parse_mode"`
  24. DisableWebPreview bool `json:"disable_web_page_preview"`
  25. }
  26. // TelegramMeta contains the telegram metadata
  27. TelegramMeta struct {
  28. BotToken string `json:"bot_token"`
  29. ChatID string `json:"chat_id"`
  30. ThreadID string `json:"thread_id"`
  31. }
  32. )
  33. // GetTelegramHook returns telegram metadata
  34. func GetTelegramHook(w *webhook_model.Webhook) *TelegramMeta {
  35. s := &TelegramMeta{}
  36. if err := json.Unmarshal([]byte(w.Meta), s); err != nil {
  37. log.Error("webhook.GetTelegramHook(%d): %v", w.ID, err)
  38. }
  39. return s
  40. }
  41. type telegramConvertor struct{}
  42. // Create implements PayloadConvertor Create method
  43. func (t telegramConvertor) Create(p *api.CreatePayload) (TelegramPayload, error) {
  44. // created tag/branch
  45. refName := git.RefName(p.Ref).ShortName()
  46. title := fmt.Sprintf(`[%s] %s %s created`,
  47. htmlLinkFormatter(p.Repo.HTMLURL, p.Repo.FullName),
  48. html.EscapeString(p.RefType),
  49. htmlLinkFormatter(p.Repo.HTMLURL+"/src/"+util.PathEscapeSegments(refName), refName),
  50. )
  51. return createTelegramPayloadHTML(title), nil
  52. }
  53. // Delete implements PayloadConvertor Delete method
  54. func (t telegramConvertor) Delete(p *api.DeletePayload) (TelegramPayload, error) {
  55. // created tag/branch
  56. refName := git.RefName(p.Ref).ShortName()
  57. title := fmt.Sprintf(`[%s] %s %s deleted`,
  58. htmlLinkFormatter(p.Repo.HTMLURL, p.Repo.FullName),
  59. html.EscapeString(p.RefType),
  60. htmlLinkFormatter(p.Repo.HTMLURL+"/src/"+util.PathEscapeSegments(refName), refName),
  61. )
  62. return createTelegramPayloadHTML(title), nil
  63. }
  64. // Fork implements PayloadConvertor Fork method
  65. func (t telegramConvertor) Fork(p *api.ForkPayload) (TelegramPayload, error) {
  66. title := fmt.Sprintf(`%s is forked to %s`, html.EscapeString(p.Forkee.FullName), htmlLinkFormatter(p.Repo.HTMLURL, p.Repo.FullName))
  67. return createTelegramPayloadHTML(title), nil
  68. }
  69. // Push implements PayloadConvertor Push method
  70. func (t telegramConvertor) Push(p *api.PushPayload) (TelegramPayload, error) {
  71. branchName := git.RefName(p.Ref).ShortName()
  72. var titleLink, commitDesc string
  73. if p.TotalCommits == 1 {
  74. commitDesc = "1 new commit"
  75. titleLink = p.Commits[0].URL
  76. } else {
  77. commitDesc = fmt.Sprintf("%d new commits", p.TotalCommits)
  78. titleLink = p.CompareURL
  79. }
  80. if titleLink == "" {
  81. titleLink = p.Repo.HTMLURL + "/src/" + util.PathEscapeSegments(branchName)
  82. }
  83. title := fmt.Sprintf(`[%s:%s] %s`, htmlLinkFormatter(p.Repo.HTMLURL, p.Repo.FullName), htmlLinkFormatter(titleLink, branchName), html.EscapeString(commitDesc))
  84. var htmlCommits string
  85. for _, commit := range p.Commits {
  86. htmlCommits += fmt.Sprintf("\n[%s] %s", htmlLinkFormatter(commit.URL, commit.ID[:7]), html.EscapeString(strings.TrimRight(commit.Message, "\r\n")))
  87. if commit.Author != nil {
  88. htmlCommits += " - " + html.EscapeString(commit.Author.Name)
  89. }
  90. }
  91. return createTelegramPayloadHTML(title + htmlCommits), nil
  92. }
  93. // Issue implements PayloadConvertor Issue method
  94. func (t telegramConvertor) Issue(p *api.IssuePayload) (TelegramPayload, error) {
  95. text, _, extraMarkdown, _ := getIssuesPayloadInfo(p, htmlLinkFormatter, true)
  96. // TODO: at the moment the markdown can't be rendered easily because it has context-aware links (eg: attachments)
  97. return createTelegramPayloadHTML(text + "\n\n" + html.EscapeString(extraMarkdown)), nil
  98. }
  99. // IssueComment implements PayloadConvertor IssueComment method
  100. func (t telegramConvertor) IssueComment(p *api.IssueCommentPayload) (TelegramPayload, error) {
  101. text, _, _ := getIssueCommentPayloadInfo(p, htmlLinkFormatter, true)
  102. return createTelegramPayloadHTML(text + "\n" + html.EscapeString(p.Comment.Body)), nil
  103. }
  104. // PullRequest implements PayloadConvertor PullRequest method
  105. func (t telegramConvertor) PullRequest(p *api.PullRequestPayload) (TelegramPayload, error) {
  106. text, _, extraMarkdown, _ := getPullRequestPayloadInfo(p, htmlLinkFormatter, true)
  107. return createTelegramPayloadHTML(text + "\n" + html.EscapeString(extraMarkdown)), nil
  108. }
  109. // Review implements PayloadConvertor Review method
  110. func (t telegramConvertor) Review(p *api.PullRequestPayload, event webhook_module.HookEventType) (TelegramPayload, error) {
  111. var text, extraMarkdown string
  112. switch p.Action {
  113. case api.HookIssueReviewed:
  114. action, err := parseHookPullRequestEventType(event)
  115. if err != nil {
  116. return TelegramPayload{}, err
  117. }
  118. text = fmt.Sprintf("[%s] Pull request review %s: #%d %s", html.EscapeString(p.Repository.FullName), html.EscapeString(action), p.Index, html.EscapeString(p.PullRequest.Title))
  119. extraMarkdown = p.Review.Content
  120. }
  121. return createTelegramPayloadHTML(text + "\n" + html.EscapeString(extraMarkdown)), nil
  122. }
  123. // Repository implements PayloadConvertor Repository method
  124. func (t telegramConvertor) Repository(p *api.RepositoryPayload) (TelegramPayload, error) {
  125. var title string
  126. switch p.Action {
  127. case api.HookRepoCreated:
  128. title = fmt.Sprintf(`[%s] Repository created`, htmlLinkFormatter(p.Repository.HTMLURL, p.Repository.FullName))
  129. return createTelegramPayloadHTML(title), nil
  130. case api.HookRepoDeleted:
  131. title = fmt.Sprintf("[%s] Repository deleted", html.EscapeString(p.Repository.FullName))
  132. return createTelegramPayloadHTML(title), nil
  133. }
  134. return TelegramPayload{}, nil
  135. }
  136. // Wiki implements PayloadConvertor Wiki method
  137. func (t telegramConvertor) Wiki(p *api.WikiPayload) (TelegramPayload, error) {
  138. text, _, _ := getWikiPayloadInfo(p, htmlLinkFormatter, true)
  139. return createTelegramPayloadHTML(text), nil
  140. }
  141. // Release implements PayloadConvertor Release method
  142. func (t telegramConvertor) Release(p *api.ReleasePayload) (TelegramPayload, error) {
  143. text, _ := getReleasePayloadInfo(p, htmlLinkFormatter, true)
  144. return createTelegramPayloadHTML(text), nil
  145. }
  146. func (t telegramConvertor) Package(p *api.PackagePayload) (TelegramPayload, error) {
  147. text, _ := getPackagePayloadInfo(p, htmlLinkFormatter, true)
  148. return createTelegramPayloadHTML(text), nil
  149. }
  150. func (t telegramConvertor) Status(p *api.CommitStatusPayload) (TelegramPayload, error) {
  151. text, _ := getStatusPayloadInfo(p, htmlLinkFormatter, true)
  152. return createTelegramPayloadHTML(text), nil
  153. }
  154. func (telegramConvertor) WorkflowRun(p *api.WorkflowRunPayload) (TelegramPayload, error) {
  155. text, _ := getWorkflowRunPayloadInfo(p, htmlLinkFormatter, true)
  156. return createTelegramPayloadHTML(text), nil
  157. }
  158. func (telegramConvertor) WorkflowJob(p *api.WorkflowJobPayload) (TelegramPayload, error) {
  159. text, _ := getWorkflowJobPayloadInfo(p, htmlLinkFormatter, true)
  160. return createTelegramPayloadHTML(text), nil
  161. }
  162. func createTelegramPayloadHTML(msgHTML string) TelegramPayload {
  163. // https://core.telegram.org/bots/api#formatting-options
  164. return TelegramPayload{
  165. Message: strings.TrimSpace(string(markup.Sanitize(msgHTML))),
  166. ParseMode: "HTML",
  167. DisableWebPreview: true,
  168. }
  169. }
  170. func newTelegramRequest(_ context.Context, w *webhook_model.Webhook, t *webhook_model.HookTask) (*http.Request, []byte, error) {
  171. var pc payloadConvertor[TelegramPayload] = telegramConvertor{}
  172. return newJSONRequest(pc, w, t, true)
  173. }
  174. func init() {
  175. RegisterWebhookRequester(webhook_module.TELEGRAM, newTelegramRequest)
  176. }