1// Copyright 2021 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 feed 6 7import ( 8 "fmt" 9 "html" 10 "net/url" 11 "strconv" 12 "strings" 13 14 "code.gitea.io/gitea/models" 15 "code.gitea.io/gitea/modules/context" 16 "code.gitea.io/gitea/modules/setting" 17 "code.gitea.io/gitea/modules/templates" 18 "code.gitea.io/gitea/modules/util" 19 20 "github.com/gorilla/feeds" 21) 22 23func toBranchLink(act *models.Action) string { 24 return act.GetRepoLink() + "/src/branch/" + util.PathEscapeSegments(act.GetBranch()) 25} 26 27func toTagLink(act *models.Action) string { 28 return act.GetRepoLink() + "/src/tag/" + util.PathEscapeSegments(act.GetTag()) 29} 30 31func toIssueLink(act *models.Action) string { 32 return act.GetRepoLink() + "/issues/" + url.PathEscape(act.GetIssueInfos()[0]) 33} 34 35func toPullLink(act *models.Action) string { 36 return act.GetRepoLink() + "/pulls/" + url.PathEscape(act.GetIssueInfos()[0]) 37} 38 39func toSrcLink(act *models.Action) string { 40 return act.GetRepoLink() + "/src/" + util.PathEscapeSegments(act.GetBranch()) 41} 42 43func toReleaseLink(act *models.Action) string { 44 return act.GetRepoLink() + "/releases/tag/" + util.PathEscapeSegments(act.GetBranch()) 45} 46 47// feedActionsToFeedItems convert gitea's Action feed to feeds Item 48func feedActionsToFeedItems(ctx *context.Context, actions []*models.Action) (items []*feeds.Item, err error) { 49 for _, act := range actions { 50 act.LoadActUser() 51 52 content, desc, title := "", "", "" 53 54 link := &feeds.Link{Href: act.GetCommentLink()} 55 56 // title 57 title = act.ActUser.DisplayName() + " " 58 switch act.OpType { 59 case models.ActionCreateRepo: 60 title += ctx.TrHTMLEscapeArgs("action.create_repo", act.GetRepoLink(), act.ShortRepoPath()) 61 link.Href = act.GetRepoLink() 62 case models.ActionRenameRepo: 63 title += ctx.TrHTMLEscapeArgs("action.rename_repo", act.GetContent(), act.GetRepoLink(), act.ShortRepoPath()) 64 link.Href = act.GetRepoLink() 65 case models.ActionCommitRepo: 66 link.Href = toBranchLink(act) 67 if len(act.Content) != 0 { 68 title += ctx.TrHTMLEscapeArgs("action.commit_repo", act.GetRepoLink(), link.Href, act.GetBranch(), act.ShortRepoPath()) 69 } else { 70 title += ctx.TrHTMLEscapeArgs("action.create_branch", act.GetRepoLink(), link.Href, act.GetBranch(), act.ShortRepoPath()) 71 } 72 case models.ActionCreateIssue: 73 link.Href = toIssueLink(act) 74 title += ctx.TrHTMLEscapeArgs("action.create_issue", link.Href, act.GetIssueInfos()[0], act.ShortRepoPath()) 75 case models.ActionCreatePullRequest: 76 link.Href = toPullLink(act) 77 title += ctx.TrHTMLEscapeArgs("action.create_pull_request", link.Href, act.GetIssueInfos()[0], act.ShortRepoPath()) 78 case models.ActionTransferRepo: 79 link.Href = act.GetRepoLink() 80 title += ctx.TrHTMLEscapeArgs("action.transfer_repo", act.GetContent(), act.GetRepoLink(), act.ShortRepoPath()) 81 case models.ActionPushTag: 82 link.Href = toTagLink(act) 83 title += ctx.TrHTMLEscapeArgs("action.push_tag", act.GetRepoLink(), link.Href, act.GetTag(), act.ShortRepoPath()) 84 case models.ActionCommentIssue: 85 issueLink := toIssueLink(act) 86 if link.Href == "#" { 87 link.Href = issueLink 88 } 89 title += ctx.TrHTMLEscapeArgs("action.comment_issue", issueLink, act.GetIssueInfos()[0], act.ShortRepoPath()) 90 case models.ActionMergePullRequest: 91 pullLink := toPullLink(act) 92 if link.Href == "#" { 93 link.Href = pullLink 94 } 95 title += ctx.TrHTMLEscapeArgs("action.merge_pull_request", pullLink, act.GetIssueInfos()[0], act.ShortRepoPath()) 96 case models.ActionCloseIssue: 97 issueLink := toIssueLink(act) 98 if link.Href == "#" { 99 link.Href = issueLink 100 } 101 title += ctx.TrHTMLEscapeArgs("action.close_issue", issueLink, act.GetIssueInfos()[0], act.ShortRepoPath()) 102 case models.ActionReopenIssue: 103 issueLink := toIssueLink(act) 104 if link.Href == "#" { 105 link.Href = issueLink 106 } 107 title += ctx.TrHTMLEscapeArgs("action.reopen_issue", issueLink, act.GetIssueInfos()[0], act.ShortRepoPath()) 108 case models.ActionClosePullRequest: 109 pullLink := toPullLink(act) 110 if link.Href == "#" { 111 link.Href = pullLink 112 } 113 title += ctx.TrHTMLEscapeArgs("action.close_pull_request", pullLink, act.GetIssueInfos()[0], act.ShortRepoPath()) 114 case models.ActionReopenPullRequest: 115 pullLink := toPullLink(act) 116 if link.Href == "#" { 117 link.Href = pullLink 118 } 119 title += ctx.TrHTMLEscapeArgs("action.reopen_pull_request", pullLink, act.GetIssueInfos()[0], act.ShortRepoPath()) 120 case models.ActionDeleteTag: 121 link.Href = act.GetRepoLink() 122 title += ctx.TrHTMLEscapeArgs("action.delete_tag", act.GetRepoLink(), act.GetTag(), act.ShortRepoPath()) 123 case models.ActionDeleteBranch: 124 link.Href = act.GetRepoLink() 125 title += ctx.TrHTMLEscapeArgs("action.delete_branch", act.GetRepoLink(), html.EscapeString(act.GetBranch()), act.ShortRepoPath()) 126 case models.ActionMirrorSyncPush: 127 srcLink := toSrcLink(act) 128 if link.Href == "#" { 129 link.Href = srcLink 130 } 131 title += ctx.TrHTMLEscapeArgs("action.mirror_sync_push", act.GetRepoLink(), srcLink, act.GetBranch(), act.ShortRepoPath()) 132 case models.ActionMirrorSyncCreate: 133 srcLink := toSrcLink(act) 134 if link.Href == "#" { 135 link.Href = srcLink 136 } 137 title += ctx.TrHTMLEscapeArgs("action.mirror_sync_create", act.GetRepoLink(), srcLink, act.GetBranch(), act.ShortRepoPath()) 138 case models.ActionMirrorSyncDelete: 139 link.Href = act.GetRepoLink() 140 title += ctx.TrHTMLEscapeArgs("action.mirror_sync_delete", act.GetRepoLink(), act.GetBranch(), act.ShortRepoPath()) 141 case models.ActionApprovePullRequest: 142 pullLink := toPullLink(act) 143 title += ctx.TrHTMLEscapeArgs("action.approve_pull_request", pullLink, act.GetIssueInfos()[0], act.ShortRepoPath()) 144 case models.ActionRejectPullRequest: 145 pullLink := toPullLink(act) 146 title += ctx.TrHTMLEscapeArgs("action.reject_pull_request", pullLink, act.GetIssueInfos()[0], act.ShortRepoPath()) 147 case models.ActionCommentPull: 148 pullLink := toPullLink(act) 149 title += ctx.TrHTMLEscapeArgs("action.comment_pull", pullLink, act.GetIssueInfos()[0], act.ShortRepoPath()) 150 case models.ActionPublishRelease: 151 releaseLink := toReleaseLink(act) 152 if link.Href == "#" { 153 link.Href = releaseLink 154 } 155 title += ctx.TrHTMLEscapeArgs("action.publish_release", act.GetRepoLink(), releaseLink, act.ShortRepoPath(), act.Content) 156 case models.ActionPullReviewDismissed: 157 pullLink := toPullLink(act) 158 title += ctx.TrHTMLEscapeArgs("action.review_dismissed", pullLink, act.GetIssueInfos()[0], act.ShortRepoPath(), act.GetIssueInfos()[1]) 159 case models.ActionStarRepo: 160 link.Href = act.GetRepoLink() 161 title += ctx.TrHTMLEscapeArgs("action.starred_repo", act.GetRepoLink(), act.GetRepoPath()) 162 case models.ActionWatchRepo: 163 link.Href = act.GetRepoLink() 164 title += ctx.TrHTMLEscapeArgs("action.watched_repo", act.GetRepoLink(), act.GetRepoPath()) 165 default: 166 return nil, fmt.Errorf("unknown action type: %v", act.OpType) 167 } 168 169 // description & content 170 { 171 switch act.OpType { 172 case models.ActionCommitRepo, models.ActionMirrorSyncPush: 173 push := templates.ActionContent2Commits(act) 174 repoLink := act.GetRepoLink() 175 176 for _, commit := range push.Commits { 177 if len(desc) != 0 { 178 desc += "\n\n" 179 } 180 desc += fmt.Sprintf("<a href=\"%s\">%s</a>\n%s", 181 html.EscapeString(fmt.Sprintf("%s/commit/%s", act.GetRepoLink(), commit.Sha1)), 182 commit.Sha1, 183 templates.RenderCommitMessage(commit.Message, repoLink, nil), 184 ) 185 } 186 187 if push.Len > 1 { 188 link = &feeds.Link{Href: fmt.Sprintf("%s/%s", setting.AppSubURL, push.CompareURL)} 189 } else if push.Len == 1 { 190 link = &feeds.Link{Href: fmt.Sprintf("%s/commit/%s", act.GetRepoLink(), push.Commits[0].Sha1)} 191 } 192 193 case models.ActionCreateIssue, models.ActionCreatePullRequest: 194 desc = strings.Join(act.GetIssueInfos(), "#") 195 content = act.GetIssueContent() 196 case models.ActionCommentIssue, models.ActionApprovePullRequest, models.ActionRejectPullRequest, models.ActionCommentPull: 197 desc = act.GetIssueTitle() 198 comment := act.GetIssueInfos()[1] 199 if len(comment) != 0 { 200 desc += "\n\n" + comment 201 } 202 case models.ActionMergePullRequest: 203 desc = act.GetIssueInfos()[1] 204 case models.ActionCloseIssue, models.ActionReopenIssue, models.ActionClosePullRequest, models.ActionReopenPullRequest: 205 desc = act.GetIssueTitle() 206 case models.ActionPullReviewDismissed: 207 desc = ctx.Tr("action.review_dismissed_reason") + "\n\n" + act.GetIssueInfos()[2] 208 } 209 } 210 if len(content) == 0 { 211 content = desc 212 } 213 214 items = append(items, &feeds.Item{ 215 Title: title, 216 Link: link, 217 Description: desc, 218 Author: &feeds.Author{ 219 Name: act.ActUser.DisplayName(), 220 Email: act.ActUser.GetEmail(), 221 }, 222 Id: strconv.FormatInt(act.ID, 10), 223 Created: act.CreatedUnix.AsTime(), 224 Content: content, 225 }) 226 } 227 return 228} 229