mirror of
https://codeberg.org/forgejo/forgejo.git
synced 2025-05-31 20:02:09 +00:00
RSS/Atom support for Repos (#19055)
* support for repos * refactor * advertise the feeds via meta tags * allow feed suffix and feed header * optimize performance
This commit is contained in:
parent
780cf76f6e
commit
bc0d2c8ada
14 changed files with 188 additions and 110 deletions
|
@ -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
|
||||
return nil
|
||||
}
|
||||
|
||||
// LoadRepositories loads actions' all repositories
|
||||
func (actions ActionList) LoadRepositories() ([]*repo_model.Repository, error) {
|
||||
return actions.loadRepositories(db.GetEngine(db.DefaultContext))
|
||||
}
|
||||
|
||||
// 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,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue