Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RSS/Atom support for Repos #19055

Merged
merged 14 commits into from
Mar 13, 2022
7 changes: 4 additions & 3 deletions models/action.go
Original file line number Diff line number Diff line change
Expand Up @@ -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")
}
Expand All @@ -338,7 +338,8 @@ func GetFeeds(opts GetFeedsOptions) ([]*Action, error) {
return nil, err
}

sess := db.GetEngine(db.DefaultContext).Where(cond)
e := db.GetEngine(ctx)
6543 marked this conversation as resolved.
Show resolved Hide resolved
sess := e.Where(cond)

opts.SetDefaultValues()
sess = db.SetSessionPagination(sess, &opts)
Expand All @@ -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)
}

Expand Down
63 changes: 35 additions & 28 deletions models/action_list.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand All @@ -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 {
Expand All @@ -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)
}
50 changes: 46 additions & 4 deletions models/action_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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,
Expand All @@ -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,
Expand All @@ -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
6543 marked this conversation as resolved.
Show resolved Hide resolved
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,
Expand All @@ -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,
Expand Down
14 changes: 7 additions & 7 deletions models/fixtures/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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

Expand All @@ -21,38 +21,38 @@
user_id: 11
op_type: 1 # create repo
act_user_id: 11
repo_id: 9
repo_id: 9 # public
is_private: false

-
id: 4
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

- id: 5
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

- id: 6
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

- id: 7
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
3 changes: 2 additions & 1 deletion models/user_heatmap_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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,
Expand Down
6 changes: 3 additions & 3 deletions modules/auth/pam/pam.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
2 changes: 2 additions & 0 deletions modules/context/repo.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
18 changes: 17 additions & 1 deletion routers/web/feed/convert.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ package feed
import (
"fmt"
"html"
"net/http"
"net/url"
"strconv"
"strings"
Expand Down Expand Up @@ -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()

Expand Down Expand Up @@ -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, ""
}
Loading