diff options
author | 6543 <6543@obermui.de> | 2022-03-13 17:40:47 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-03-13 17:40:47 +0100 |
commit | bc0d2c8ada14eae81542f30a81552ed5cef8bd5d (patch) | |
tree | 5242a9e288f53cfc04e56df495a048d02a902d91 /routers | |
parent | 780cf76f6e930b5e92fd12ae1e729c5702e70afa (diff) | |
download | gitea-bc0d2c8ada14eae81542f30a81552ed5cef8bd5d.tar.gz gitea-bc0d2c8ada14eae81542f30a81552ed5cef8bd5d.zip |
RSS/Atom support for Repos (#19055)
* support for repos
* refactor
* advertise the feeds via meta tags
* allow feed suffix and feed header
* optimize performance
Diffstat (limited to 'routers')
-rw-r--r-- | routers/web/feed/convert.go | 18 | ||||
-rw-r--r-- | routers/web/feed/profile.go | 45 | ||||
-rw-r--r-- | routers/web/feed/repo.go | 44 | ||||
-rw-r--r-- | routers/web/repo/view.go | 9 | ||||
-rw-r--r-- | routers/web/user/home.go | 7 | ||||
-rw-r--r-- | routers/web/user/profile.go | 26 |
6 files changed, 85 insertions, 64 deletions
diff --git a/routers/web/feed/convert.go b/routers/web/feed/convert.go index 51df014f1d..64801a6078 100644 --- a/routers/web/feed/convert.go +++ b/routers/web/feed/convert.go @@ -7,6 +7,7 @@ package feed import ( "fmt" "html" + "net/http" "net/url" "strconv" "strings" @@ -66,7 +67,7 @@ func renderMarkdown(ctx *context.Context, act *models.Action, content string) st } // feedActionsToFeedItems convert gitea's Action feed to feeds Item -func feedActionsToFeedItems(ctx *context.Context, actions []*models.Action) (items []*feeds.Item, err error) { +func feedActionsToFeedItems(ctx *context.Context, actions models.ActionList) (items []*feeds.Item, err error) { for _, act := range actions { act.LoadActUser() @@ -247,3 +248,18 @@ func feedActionsToFeedItems(ctx *context.Context, actions []*models.Action) (ite } return } + +// GetFeedType return if it is a feed request and altered name and feed type. +func GetFeedType(name string, req *http.Request) (bool, string, string) { + if strings.HasSuffix(name, ".rss") || + strings.Contains(req.Header.Get("Accept"), "application/rss+xml") { + return true, strings.TrimSuffix(name, ".rss"), "rss" + } + + if strings.HasSuffix(name, ".atom") || + strings.Contains(req.Header.Get("Accept"), "application/atom+xml") { + return true, strings.TrimSuffix(name, ".atom"), "atom" + } + + return false, name, "" +} diff --git a/routers/web/feed/profile.go b/routers/web/feed/profile.go index 4c1eff04a9..a7b8efcdbe 100644 --- a/routers/web/feed/profile.go +++ b/routers/web/feed/profile.go @@ -15,48 +15,9 @@ import ( "github.com/gorilla/feeds" ) -// RetrieveFeeds loads feeds for the specified user -func RetrieveFeeds(ctx *context.Context, options models.GetFeedsOptions) []*models.Action { - actions, err := models.GetFeeds(options) - if err != nil { - ctx.ServerError("GetFeeds", err) - return nil - } - - // TODO: move load repoOwner of act.Repo into models.GetFeeds->loadAttributes() - { - userCache := map[int64]*user_model.User{options.RequestedUser.ID: options.RequestedUser} - if ctx.User != nil { - userCache[ctx.User.ID] = ctx.User - } - for _, act := range actions { - if act.ActUser != nil { - userCache[act.ActUserID] = act.ActUser - } - } - for _, act := range actions { - repoOwner, ok := userCache[act.Repo.OwnerID] - if !ok { - repoOwner, err = user_model.GetUserByID(act.Repo.OwnerID) - if err != nil { - if user_model.IsErrUserNotExist(err) { - continue - } - ctx.ServerError("GetUserByID", err) - return nil - } - userCache[repoOwner.ID] = repoOwner - } - act.Repo.Owner = repoOwner - } - } - - return actions -} - // ShowUserFeed show user activity as RSS / Atom feed func ShowUserFeed(ctx *context.Context, ctxUser *user_model.User, formatType string) { - actions := RetrieveFeeds(ctx, models.GetFeedsOptions{ + actions, err := models.GetFeeds(ctx, models.GetFeedsOptions{ RequestedUser: ctxUser, Actor: ctx.User, IncludePrivate: false, @@ -64,7 +25,8 @@ func ShowUserFeed(ctx *context.Context, ctxUser *user_model.User, formatType str IncludeDeleted: false, Date: ctx.FormString("date"), }) - if ctx.Written() { + if err != nil { + ctx.ServerError("GetFeeds", err) return } @@ -75,7 +37,6 @@ func ShowUserFeed(ctx *context.Context, ctxUser *user_model.User, formatType str Created: time.Now(), } - var err error feed.Items, err = feedActionsToFeedItems(ctx, actions) if err != nil { ctx.ServerError("convert feed", err) diff --git a/routers/web/feed/repo.go b/routers/web/feed/repo.go new file mode 100644 index 0000000000..53fb8148e0 --- /dev/null +++ b/routers/web/feed/repo.go @@ -0,0 +1,44 @@ +// Copyright 2022 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. + +package feed + +import ( + "time" + + "code.gitea.io/gitea/models" + repo_model "code.gitea.io/gitea/models/repo" + "code.gitea.io/gitea/modules/context" + + "github.com/gorilla/feeds" +) + +// ShowRepoFeed shows user activity on the repo as RSS / Atom feed +func ShowRepoFeed(ctx *context.Context, repo *repo_model.Repository, formatType string) { + actions, err := models.GetFeeds(ctx, models.GetFeedsOptions{ + RequestedRepo: repo, + Actor: ctx.User, + IncludePrivate: true, + Date: ctx.FormString("date"), + }) + if err != nil { + ctx.ServerError("GetFeeds", err) + return + } + + feed := &feeds.Feed{ + Title: ctx.Tr("home.feed_of", repo.FullName()), + Link: &feeds.Link{Href: repo.HTMLURL()}, + Description: repo.Description, + Created: time.Now(), + } + + feed.Items, err = feedActionsToFeedItems(ctx, actions) + if err != nil { + ctx.ServerError("convert feed", err) + return + } + + writeFeed(ctx, feed, formatType) +} diff --git a/routers/web/repo/view.go b/routers/web/repo/view.go index 9ff72b2102..5293d3c6a3 100644 --- a/routers/web/repo/view.go +++ b/routers/web/repo/view.go @@ -38,6 +38,7 @@ import ( "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/typesniffer" "code.gitea.io/gitea/modules/util" + "code.gitea.io/gitea/routers/web/feed" ) const ( @@ -691,6 +692,14 @@ func checkHomeCodeViewable(ctx *context.Context) { // Home render repository home page func Home(ctx *context.Context) { + isFeed, _, showFeedType := feed.GetFeedType(ctx.Params(":reponame"), ctx.Req) + if isFeed { + feed.ShowRepoFeed(ctx, ctx.Repo.Repository, showFeedType) + return + } + + ctx.Data["FeedURL"] = ctx.Repo.Repository.HTMLURL() + checkHomeCodeViewable(ctx) if ctx.Written() { return diff --git a/routers/web/user/home.go b/routers/web/user/home.go index 379e1f8e20..877aa45280 100644 --- a/routers/web/user/home.go +++ b/routers/web/user/home.go @@ -29,7 +29,6 @@ import ( "code.gitea.io/gitea/modules/markup/markdown" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/util" - "code.gitea.io/gitea/routers/web/feed" issue_service "code.gitea.io/gitea/services/issue" pull_service "code.gitea.io/gitea/services/pull" @@ -131,7 +130,7 @@ func Dashboard(ctx *context.Context) { ctx.Data["MirrorCount"] = len(mirrors) ctx.Data["Mirrors"] = mirrors - ctx.Data["Feeds"] = feed.RetrieveFeeds(ctx, models.GetFeedsOptions{ + ctx.Data["Feeds"], err = models.GetFeeds(ctx, models.GetFeedsOptions{ RequestedUser: ctxUser, RequestedTeam: ctx.Org.Team, Actor: ctx.User, @@ -140,8 +139,8 @@ func Dashboard(ctx *context.Context) { IncludeDeleted: false, Date: ctx.FormString("date"), }) - - if ctx.Written() { + if err != nil { + ctx.ServerError("GetFeeds", err) return } diff --git a/routers/web/user/profile.go b/routers/web/user/profile.go index b4198ef8fd..b84cee2b3a 100644 --- a/routers/web/user/profile.go +++ b/routers/web/user/profile.go @@ -74,19 +74,7 @@ func Profile(ctx *context.Context) { uname = strings.TrimSuffix(uname, ".gpg") } - showFeedType := "" - if strings.HasSuffix(uname, ".rss") { - showFeedType = "rss" - uname = strings.TrimSuffix(uname, ".rss") - } else if strings.Contains(ctx.Req.Header.Get("Accept"), "application/rss+xml") { - showFeedType = "rss" - } - if strings.HasSuffix(uname, ".atom") { - showFeedType = "atom" - uname = strings.TrimSuffix(uname, ".atom") - } else if strings.Contains(ctx.Req.Header.Get("Accept"), "application/atom+xml") { - showFeedType = "atom" - } + isShowFeed, uname, showFeedType := feed.GetFeedType(uname, ctx.Req) ctxUser := GetUserByName(ctx, uname) if ctx.Written() { @@ -95,7 +83,7 @@ func Profile(ctx *context.Context) { if ctxUser.IsOrganization() { // Show Org RSS feed - if len(showFeedType) != 0 { + if isShowFeed { feed.ShowUserFeed(ctx, ctxUser, showFeedType) return } @@ -123,11 +111,14 @@ func Profile(ctx *context.Context) { } // Show User RSS feed - if len(showFeedType) != 0 { + if isShowFeed { feed.ShowUserFeed(ctx, ctxUser, showFeedType) return } + // advertise feed via meta tag + ctx.Data["FeedURL"] = ctxUser.HTMLURL() + // Show OpenID URIs openIDs, err := user_model.GetUserOpenIDs(ctxUser.ID) if err != nil { @@ -259,7 +250,7 @@ func Profile(ctx *context.Context) { total = ctxUser.NumFollowing case "activity": - ctx.Data["Feeds"] = feed.RetrieveFeeds(ctx, models.GetFeedsOptions{ + ctx.Data["Feeds"], err = models.GetFeeds(ctx, models.GetFeedsOptions{ RequestedUser: ctxUser, Actor: ctx.User, IncludePrivate: showPrivate, @@ -267,7 +258,8 @@ func Profile(ctx *context.Context) { IncludeDeleted: false, Date: ctx.FormString("date"), }) - if ctx.Written() { + if err != nil { + ctx.ServerError("GetFeeds", err) return } case "stars": |