Changes
14 changed files (+188/-110)
-
-
@@ -328,7 +328,7 @@ type GetFeedsOptions struct {} // GetFeeds returns actions according to the provided options func GetFeeds(opts GetFeedsOptions) ([]*Action, error) { func GetFeeds(ctx context.Context, opts GetFeedsOptions) (ActionList, error) { if opts.RequestedUser == nil && opts.RequestedTeam == nil && opts.RequestedRepo == nil { return nil, fmt.Errorf("need at least one of these filters: RequestedUser, RequestedTeam, RequestedRepo") }
-
@@ -338,7 +338,8 @@ func GetFeeds(opts GetFeedsOptions) ([]*Action, error) {return nil, err } sess := db.GetEngine(db.DefaultContext).Where(cond) e := db.GetEngine(ctx) sess := e.Where(cond) opts.SetDefaultValues() sess = db.SetSessionPagination(sess, &opts)
-
@@ -349,7 +350,7 @@ func GetFeeds(opts GetFeedsOptions) ([]*Action, error) {return nil, fmt.Errorf("Find: %v", err) } if err := ActionList(actions).LoadAttributes(); err != nil { if err := ActionList(actions).loadAttributes(e); err != nil { return nil, fmt.Errorf("LoadAttributes: %v", err) }
-
-
-
@@ -25,7 +25,7 @@ func (actions ActionList) getUserIDs() []int64 {return keysInt64(userIDs) } func (actions ActionList) loadUsers(e db.Engine) ([]*user_model.User, error) { func (actions ActionList) loadUsers(e db.Engine) (map[int64]*user_model.User, error) { if len(actions) == 0 { return nil, nil }
-
@@ -42,12 +42,7 @@ func (actions ActionList) loadUsers(e db.Engine) ([]*user_model.User, error) {for _, action := range actions { action.ActUser = userMaps[action.ActUserID] } return valuesUser(userMaps), nil } // LoadUsers loads actions' all users func (actions ActionList) LoadUsers() ([]*user_model.User, error) { return actions.loadUsers(db.GetEngine(db.DefaultContext)) return userMaps, nil } func (actions ActionList) getRepoIDs() []int64 {
-
@@ -60,45 +55,57 @@ func (actions ActionList) getRepoIDs() []int64 {return keysInt64(repoIDs) } func (actions ActionList) loadRepositories(e db.Engine) ([]*repo_model.Repository, error) { func (actions ActionList) loadRepositories(e db.Engine) error { if len(actions) == 0 { return nil, nil return nil } repoIDs := actions.getRepoIDs() repoMaps := make(map[int64]*repo_model.Repository, len(repoIDs)) err := e. In("id", repoIDs). Find(&repoMaps) err := e.In("id", repoIDs).Find(&repoMaps) if err != nil { return nil, fmt.Errorf("find repository: %v", err) return fmt.Errorf("find repository: %v", err) } for _, action := range actions { action.Repo = repoMaps[action.RepoID] } return valuesRepository(repoMaps), nil } // LoadRepositories loads actions' all repositories func (actions ActionList) LoadRepositories() ([]*repo_model.Repository, error) { return actions.loadRepositories(db.GetEngine(db.DefaultContext)) return nil } // loadAttributes loads all attributes func (actions ActionList) loadAttributes(e db.Engine) (err error) { if _, err = actions.loadUsers(e); err != nil { return func (actions ActionList) loadRepoOwner(e db.Engine, userMap map[int64]*user_model.User) (err error) { if userMap == nil { userMap = make(map[int64]*user_model.User) } if _, err = actions.loadRepositories(e); err != nil { return for _, action := range actions { repoOwner, ok := userMap[action.Repo.OwnerID] if !ok { repoOwner, err = user_model.GetUserByID(action.Repo.OwnerID) if err != nil { if user_model.IsErrUserNotExist(err) { continue } return err } userMap[repoOwner.ID] = repoOwner } action.Repo.Owner = repoOwner } return nil } // LoadAttributes loads attributes of the actions func (actions ActionList) LoadAttributes() error { return actions.loadAttributes(db.GetEngine(db.DefaultContext)) // loadAttributes loads all attributes func (actions ActionList) loadAttributes(e db.Engine) error { userMap, err := actions.loadUsers(e) if err != nil { return err } if err := actions.loadRepositories(e); err != nil { return err } return actions.loadRepoOwner(e, userMap) }
-
-
-
@@ -8,6 +8,7 @@ import ("path" "testing" "code.gitea.io/gitea/models/db" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unittest" user_model "code.gitea.io/gitea/models/user"
-
@@ -39,7 +40,7 @@ func TestGetFeeds(t *testing.T) {assert.NoError(t, unittest.PrepareTestDatabase()) user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) actions, err := GetFeeds(GetFeedsOptions{ actions, err := GetFeeds(db.DefaultContext, GetFeedsOptions{ RequestedUser: user, Actor: user, IncludePrivate: true,
-
@@ -52,7 +53,7 @@ func TestGetFeeds(t *testing.T) {assert.EqualValues(t, user.ID, actions[0].UserID) } actions, err = GetFeeds(GetFeedsOptions{ actions, err = GetFeeds(db.DefaultContext, GetFeedsOptions{ RequestedUser: user, Actor: user, IncludePrivate: false,
-
@@ -62,13 +63,54 @@ func TestGetFeeds(t *testing.T) {assert.Len(t, actions, 0) } func TestGetFeedsForRepos(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) privRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2}).(*repo_model.Repository) pubRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 8}).(*repo_model.Repository) // private repo & no login actions, err := GetFeeds(db.DefaultContext, GetFeedsOptions{ RequestedRepo: privRepo, IncludePrivate: true, }) assert.NoError(t, err) assert.Len(t, actions, 0) // public repo & no login actions, err = GetFeeds(db.DefaultContext, GetFeedsOptions{ RequestedRepo: pubRepo, IncludePrivate: true, }) assert.NoError(t, err) assert.Len(t, actions, 1) // private repo and login actions, err = GetFeeds(db.DefaultContext, GetFeedsOptions{ RequestedRepo: privRepo, IncludePrivate: true, Actor: user, }) assert.NoError(t, err) assert.Len(t, actions, 1) // public repo & login actions, err = GetFeeds(db.DefaultContext, GetFeedsOptions{ RequestedRepo: pubRepo, IncludePrivate: true, Actor: user, }) assert.NoError(t, err) assert.Len(t, actions, 1) } func TestGetFeeds2(t *testing.T) { // test with an organization user assert.NoError(t, unittest.PrepareTestDatabase()) org := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3}).(*user_model.User) user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) actions, err := GetFeeds(GetFeedsOptions{ actions, err := GetFeeds(db.DefaultContext, GetFeedsOptions{ RequestedUser: org, Actor: user, IncludePrivate: true,
-
@@ -82,7 +124,7 @@ func TestGetFeeds2(t *testing.T) {assert.EqualValues(t, org.ID, actions[0].UserID) } actions, err = GetFeeds(GetFeedsOptions{ actions, err = GetFeeds(db.DefaultContext, GetFeedsOptions{ RequestedUser: org, Actor: user, IncludePrivate: false,
-
-
-
@@ -3,7 +3,7 @@user_id: 2 op_type: 12 # close issue act_user_id: 2 repo_id: 2 repo_id: 2 # private is_private: true created_unix: 1603228283
-
@@ -12,7 +12,7 @@user_id: 3 op_type: 2 # rename repo act_user_id: 2 repo_id: 3 repo_id: 3 # private is_private: true content: oldRepoName
-
@@ -21,7 +21,7 @@user_id: 11 op_type: 1 # create repo act_user_id: 11 repo_id: 9 repo_id: 9 # public is_private: false -
-
@@ -29,7 +29,7 @@user_id: 16 op_type: 12 # close issue act_user_id: 16 repo_id: 22 repo_id: 22 # private is_private: true created_unix: 1603267920
-
@@ -37,7 +37,7 @@user_id: 10 op_type: 1 # create repo act_user_id: 10 repo_id: 6 repo_id: 6 # private is_private: true created_unix: 1603010100
-
@@ -45,7 +45,7 @@user_id: 10 op_type: 1 # create repo act_user_id: 10 repo_id: 7 repo_id: 7 # private is_private: true created_unix: 1603011300
-
@@ -53,6 +53,6 @@user_id: 10 op_type: 1 # create repo act_user_id: 10 repo_id: 8 repo_id: 8 # public is_private: false created_unix: 1603011540 # grouped with id:7
-
-
-
@@ -9,6 +9,7 @@ import ("testing" "time" "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/unittest" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/json"
-
@@ -72,7 +73,7 @@ func TestGetUserHeatmapDataByUser(t *testing.T) {} // get the action for comparison actions, err := GetFeeds(GetFeedsOptions{ actions, err := GetFeeds(db.DefaultContext, GetFeedsOptions{ RequestedUser: user, Actor: doer, IncludePrivate: true,
-
-
-
@@ -34,10 +34,10 @@ func Auth(serviceName, userName, passwd string) (string, error) {if err = t.Authenticate(0); err != nil { return "", err } if err = t.AcctMgmt(0); err != nil { return "", err } return "", err } // PAM login names might suffer transformations in the PAM stack. // We should take whatever the PAM stack returns for it.
-
-
-
@@ -418,6 +418,8 @@ func RepoAssignment(ctx *Context) (cancel context.CancelFunc) {userName := ctx.Params(":username") repoName := ctx.Params(":reponame") repoName = strings.TrimSuffix(repoName, ".git") repoName = strings.TrimSuffix(repoName, ".rss") repoName = strings.TrimSuffix(repoName, ".atom") // Check if the user is the same as the repository owner if ctx.IsSigned && ctx.User.LowerName == strings.ToLower(userName) {
-
-
-
@@ -7,6 +7,7 @@ package feedimport ( "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, "" }
-
-
-
@@ -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 strIncludeDeleted: 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 strCreated: time.Now(), } var err error feed.Items, err = feedActionsToFeedItems(ctx, actions) if err != nil { ctx.ServerError("convert feed", err)
-
-
routers/web/feed/repo.go (new)
-
@@ -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) }
-
-
-
@@ -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
-
-
-
@@ -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 }
-
-
-
@@ -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":
-
-
-
@@ -14,6 +14,10 @@{{if .GoGetImport}} <meta name="go-import" content="{{.GoGetImport}} git {{.CloneLink.HTTPS}}"> <meta name="go-source" content="{{.GoGetImport}} _ {{.GoDocDirectory}} {{.GoDocFile}}"> {{end}} {{if .FeedURL}} <link rel="alternate" type="application/atom+xml" title="" href="{{.FeedURL}}.atom"> <link rel="alternate" type="application/rss+xml" title="" href="{{.FeedURL}}.rss"> {{end}} <script> <!-- /* eslint-disable */ -->
-