mirror of
https://github.com/go-gitea/gitea
synced 2024-12-22 18:28:01 +01:00
Move GetFeeds to service layer (#32526)
Move GetFeeds from models to service layer, no code change.
This commit is contained in:
parent
93640993e3
commit
1ed5f379b9
@ -448,65 +448,13 @@ type GetFeedsOptions struct {
|
|||||||
Date string // the day we want activity for: YYYY-MM-DD
|
Date string // the day we want activity for: YYYY-MM-DD
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetFeeds returns actions according to the provided options
|
|
||||||
func GetFeeds(ctx context.Context, opts GetFeedsOptions) (ActionList, int64, error) {
|
|
||||||
if opts.RequestedUser == nil && opts.RequestedTeam == nil && opts.RequestedRepo == nil {
|
|
||||||
return nil, 0, fmt.Errorf("need at least one of these filters: RequestedUser, RequestedTeam, RequestedRepo")
|
|
||||||
}
|
|
||||||
|
|
||||||
cond, err := activityQueryCondition(ctx, opts)
|
|
||||||
if err != nil {
|
|
||||||
return nil, 0, err
|
|
||||||
}
|
|
||||||
|
|
||||||
actions := make([]*Action, 0, opts.PageSize)
|
|
||||||
var count int64
|
|
||||||
opts.SetDefaultValues()
|
|
||||||
|
|
||||||
if opts.Page < 10 { // TODO: why it's 10 but other values? It's an experience value.
|
|
||||||
sess := db.GetEngine(ctx).Where(cond)
|
|
||||||
sess = db.SetSessionPagination(sess, &opts)
|
|
||||||
|
|
||||||
count, err = sess.Desc("`action`.created_unix").FindAndCount(&actions)
|
|
||||||
if err != nil {
|
|
||||||
return nil, 0, fmt.Errorf("FindAndCount: %w", err)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// First, only query which IDs are necessary, and only then query all actions to speed up the overall query
|
|
||||||
sess := db.GetEngine(ctx).Where(cond).Select("`action`.id")
|
|
||||||
sess = db.SetSessionPagination(sess, &opts)
|
|
||||||
|
|
||||||
actionIDs := make([]int64, 0, opts.PageSize)
|
|
||||||
if err := sess.Table("action").Desc("`action`.created_unix").Find(&actionIDs); err != nil {
|
|
||||||
return nil, 0, fmt.Errorf("Find(actionsIDs): %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
count, err = db.GetEngine(ctx).Where(cond).
|
|
||||||
Table("action").
|
|
||||||
Cols("`action`.id").Count()
|
|
||||||
if err != nil {
|
|
||||||
return nil, 0, fmt.Errorf("Count: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := db.GetEngine(ctx).In("`action`.id", actionIDs).Desc("`action`.created_unix").Find(&actions); err != nil {
|
|
||||||
return nil, 0, fmt.Errorf("Find: %w", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := ActionList(actions).LoadAttributes(ctx); err != nil {
|
|
||||||
return nil, 0, fmt.Errorf("LoadAttributes: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return actions, count, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ActivityReadable return whether doer can read activities of user
|
// ActivityReadable return whether doer can read activities of user
|
||||||
func ActivityReadable(user, doer *user_model.User) bool {
|
func ActivityReadable(user, doer *user_model.User) bool {
|
||||||
return !user.KeepActivityPrivate ||
|
return !user.KeepActivityPrivate ||
|
||||||
doer != nil && (doer.IsAdmin || user.ID == doer.ID)
|
doer != nil && (doer.IsAdmin || user.ID == doer.ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func activityQueryCondition(ctx context.Context, opts GetFeedsOptions) (builder.Cond, error) {
|
func ActivityQueryCondition(ctx context.Context, opts GetFeedsOptions) (builder.Cond, error) {
|
||||||
cond := builder.NewCond()
|
cond := builder.NewCond()
|
||||||
|
|
||||||
if opts.RequestedTeam != nil && opts.RequestedUser == nil {
|
if opts.RequestedTeam != nil && opts.RequestedUser == nil {
|
||||||
|
@ -201,3 +201,55 @@ func (actions ActionList) LoadIssues(ctx context.Context) error {
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetFeeds returns actions according to the provided options
|
||||||
|
func GetFeeds(ctx context.Context, opts GetFeedsOptions) (ActionList, int64, error) {
|
||||||
|
if opts.RequestedUser == nil && opts.RequestedTeam == nil && opts.RequestedRepo == nil {
|
||||||
|
return nil, 0, fmt.Errorf("need at least one of these filters: RequestedUser, RequestedTeam, RequestedRepo")
|
||||||
|
}
|
||||||
|
|
||||||
|
cond, err := ActivityQueryCondition(ctx, opts)
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
actions := make([]*Action, 0, opts.PageSize)
|
||||||
|
var count int64
|
||||||
|
opts.SetDefaultValues()
|
||||||
|
|
||||||
|
if opts.Page < 10 { // TODO: why it's 10 but other values? It's an experience value.
|
||||||
|
sess := db.GetEngine(ctx).Where(cond)
|
||||||
|
sess = db.SetSessionPagination(sess, &opts)
|
||||||
|
|
||||||
|
count, err = sess.Desc("`action`.created_unix").FindAndCount(&actions)
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, fmt.Errorf("FindAndCount: %w", err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// First, only query which IDs are necessary, and only then query all actions to speed up the overall query
|
||||||
|
sess := db.GetEngine(ctx).Where(cond).Select("`action`.id")
|
||||||
|
sess = db.SetSessionPagination(sess, &opts)
|
||||||
|
|
||||||
|
actionIDs := make([]int64, 0, opts.PageSize)
|
||||||
|
if err := sess.Table("action").Desc("`action`.created_unix").Find(&actionIDs); err != nil {
|
||||||
|
return nil, 0, fmt.Errorf("Find(actionsIDs): %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
count, err = db.GetEngine(ctx).Where(cond).
|
||||||
|
Table("action").
|
||||||
|
Cols("`action`.id").Count()
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, fmt.Errorf("Count: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := db.GetEngine(ctx).In("`action`.id", actionIDs).Desc("`action`.created_unix").Find(&actions); err != nil {
|
||||||
|
return nil, 0, fmt.Errorf("Find: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := ActionList(actions).LoadAttributes(ctx); err != nil {
|
||||||
|
return nil, 0, fmt.Errorf("LoadAttributes: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return actions, count, nil
|
||||||
|
}
|
||||||
|
@ -42,114 +42,6 @@ func TestAction_GetRepoLink(t *testing.T) {
|
|||||||
assert.Equal(t, comment.HTMLURL(db.DefaultContext), action.GetCommentHTMLURL(db.DefaultContext))
|
assert.Equal(t, comment.HTMLURL(db.DefaultContext), action.GetCommentHTMLURL(db.DefaultContext))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetFeeds(t *testing.T) {
|
|
||||||
// test with an individual user
|
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
|
||||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
|
||||||
|
|
||||||
actions, count, err := activities_model.GetFeeds(db.DefaultContext, activities_model.GetFeedsOptions{
|
|
||||||
RequestedUser: user,
|
|
||||||
Actor: user,
|
|
||||||
IncludePrivate: true,
|
|
||||||
OnlyPerformedBy: false,
|
|
||||||
IncludeDeleted: true,
|
|
||||||
})
|
|
||||||
assert.NoError(t, err)
|
|
||||||
if assert.Len(t, actions, 1) {
|
|
||||||
assert.EqualValues(t, 1, actions[0].ID)
|
|
||||||
assert.EqualValues(t, user.ID, actions[0].UserID)
|
|
||||||
}
|
|
||||||
assert.Equal(t, int64(1), count)
|
|
||||||
|
|
||||||
actions, count, err = activities_model.GetFeeds(db.DefaultContext, activities_model.GetFeedsOptions{
|
|
||||||
RequestedUser: user,
|
|
||||||
Actor: user,
|
|
||||||
IncludePrivate: false,
|
|
||||||
OnlyPerformedBy: false,
|
|
||||||
})
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.Len(t, actions, 0)
|
|
||||||
assert.Equal(t, int64(0), count)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGetFeedsForRepos(t *testing.T) {
|
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
|
||||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
|
||||||
privRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2})
|
|
||||||
pubRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 8})
|
|
||||||
|
|
||||||
// private repo & no login
|
|
||||||
actions, count, err := activities_model.GetFeeds(db.DefaultContext, activities_model.GetFeedsOptions{
|
|
||||||
RequestedRepo: privRepo,
|
|
||||||
IncludePrivate: true,
|
|
||||||
})
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.Len(t, actions, 0)
|
|
||||||
assert.Equal(t, int64(0), count)
|
|
||||||
|
|
||||||
// public repo & no login
|
|
||||||
actions, count, err = activities_model.GetFeeds(db.DefaultContext, activities_model.GetFeedsOptions{
|
|
||||||
RequestedRepo: pubRepo,
|
|
||||||
IncludePrivate: true,
|
|
||||||
})
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.Len(t, actions, 1)
|
|
||||||
assert.Equal(t, int64(1), count)
|
|
||||||
|
|
||||||
// private repo and login
|
|
||||||
actions, count, err = activities_model.GetFeeds(db.DefaultContext, activities_model.GetFeedsOptions{
|
|
||||||
RequestedRepo: privRepo,
|
|
||||||
IncludePrivate: true,
|
|
||||||
Actor: user,
|
|
||||||
})
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.Len(t, actions, 1)
|
|
||||||
assert.Equal(t, int64(1), count)
|
|
||||||
|
|
||||||
// public repo & login
|
|
||||||
actions, count, err = activities_model.GetFeeds(db.DefaultContext, activities_model.GetFeedsOptions{
|
|
||||||
RequestedRepo: pubRepo,
|
|
||||||
IncludePrivate: true,
|
|
||||||
Actor: user,
|
|
||||||
})
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.Len(t, actions, 1)
|
|
||||||
assert.Equal(t, int64(1), count)
|
|
||||||
}
|
|
||||||
|
|
||||||
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 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
|
||||||
|
|
||||||
actions, count, err := activities_model.GetFeeds(db.DefaultContext, activities_model.GetFeedsOptions{
|
|
||||||
RequestedUser: org,
|
|
||||||
Actor: user,
|
|
||||||
IncludePrivate: true,
|
|
||||||
OnlyPerformedBy: false,
|
|
||||||
IncludeDeleted: true,
|
|
||||||
})
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.Len(t, actions, 1)
|
|
||||||
if assert.Len(t, actions, 1) {
|
|
||||||
assert.EqualValues(t, 2, actions[0].ID)
|
|
||||||
assert.EqualValues(t, org.ID, actions[0].UserID)
|
|
||||||
}
|
|
||||||
assert.Equal(t, int64(1), count)
|
|
||||||
|
|
||||||
actions, count, err = activities_model.GetFeeds(db.DefaultContext, activities_model.GetFeedsOptions{
|
|
||||||
RequestedUser: org,
|
|
||||||
Actor: user,
|
|
||||||
IncludePrivate: false,
|
|
||||||
OnlyPerformedBy: false,
|
|
||||||
IncludeDeleted: true,
|
|
||||||
})
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.Len(t, actions, 0)
|
|
||||||
assert.Equal(t, int64(0), count)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestActivityReadable(t *testing.T) {
|
func TestActivityReadable(t *testing.T) {
|
||||||
tt := []struct {
|
tt := []struct {
|
||||||
desc string
|
desc string
|
||||||
@ -227,26 +119,6 @@ func TestNotifyWatchers(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetFeedsCorrupted(t *testing.T) {
|
|
||||||
// Now we will not check for corrupted data in the feeds
|
|
||||||
// users should run doctor to fix their data
|
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
|
||||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1})
|
|
||||||
unittest.AssertExistsAndLoadBean(t, &activities_model.Action{
|
|
||||||
ID: 8,
|
|
||||||
RepoID: 1700,
|
|
||||||
})
|
|
||||||
|
|
||||||
actions, count, err := activities_model.GetFeeds(db.DefaultContext, activities_model.GetFeedsOptions{
|
|
||||||
RequestedUser: user,
|
|
||||||
Actor: user,
|
|
||||||
IncludePrivate: true,
|
|
||||||
})
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.Len(t, actions, 1)
|
|
||||||
assert.Equal(t, int64(1), count)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestConsistencyUpdateAction(t *testing.T) {
|
func TestConsistencyUpdateAction(t *testing.T) {
|
||||||
if !setting.Database.Type.IsSQLite3() {
|
if !setting.Database.Type.IsSQLite3() {
|
||||||
t.Skip("Test is only for SQLite database.")
|
t.Skip("Test is only for SQLite database.")
|
||||||
@ -322,24 +194,3 @@ func TestDeleteIssueActions(t *testing.T) {
|
|||||||
assert.NoError(t, activities_model.DeleteIssueActions(db.DefaultContext, issue.RepoID, issue.ID, issue.Index))
|
assert.NoError(t, activities_model.DeleteIssueActions(db.DefaultContext, issue.RepoID, issue.ID, issue.Index))
|
||||||
unittest.AssertCount(t, &activities_model.Action{}, 0)
|
unittest.AssertCount(t, &activities_model.Action{}, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRepoActions(t *testing.T) {
|
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
|
||||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
|
||||||
_ = db.TruncateBeans(db.DefaultContext, &activities_model.Action{})
|
|
||||||
for i := 0; i < 3; i++ {
|
|
||||||
_ = db.Insert(db.DefaultContext, &activities_model.Action{
|
|
||||||
UserID: 2 + int64(i),
|
|
||||||
ActUserID: 2,
|
|
||||||
RepoID: repo.ID,
|
|
||||||
OpType: activities_model.ActionCommentIssue,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
count, _ := db.Count[activities_model.Action](db.DefaultContext, &db.ListOptions{})
|
|
||||||
assert.EqualValues(t, 3, count)
|
|
||||||
actions, _, err := activities_model.GetFeeds(db.DefaultContext, activities_model.GetFeedsOptions{
|
|
||||||
RequestedRepo: repo,
|
|
||||||
})
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.Len(t, actions, 1)
|
|
||||||
}
|
|
||||||
|
@ -47,7 +47,7 @@ func getUserHeatmapData(ctx context.Context, user *user_model.User, team *organi
|
|||||||
groupByName = groupBy
|
groupByName = groupBy
|
||||||
}
|
}
|
||||||
|
|
||||||
cond, err := activityQueryCondition(ctx, GetFeedsOptions{
|
cond, err := ActivityQueryCondition(ctx, GetFeedsOptions{
|
||||||
RequestedUser: user,
|
RequestedUser: user,
|
||||||
RequestedTeam: team,
|
RequestedTeam: team,
|
||||||
Actor: doer,
|
Actor: doer,
|
||||||
|
@ -19,6 +19,7 @@ import (
|
|||||||
"code.gitea.io/gitea/routers/api/v1/utils"
|
"code.gitea.io/gitea/routers/api/v1/utils"
|
||||||
"code.gitea.io/gitea/services/context"
|
"code.gitea.io/gitea/services/context"
|
||||||
"code.gitea.io/gitea/services/convert"
|
"code.gitea.io/gitea/services/convert"
|
||||||
|
feed_service "code.gitea.io/gitea/services/feed"
|
||||||
"code.gitea.io/gitea/services/org"
|
"code.gitea.io/gitea/services/org"
|
||||||
user_service "code.gitea.io/gitea/services/user"
|
user_service "code.gitea.io/gitea/services/user"
|
||||||
)
|
)
|
||||||
@ -447,7 +448,7 @@ func ListOrgActivityFeeds(ctx *context.APIContext) {
|
|||||||
ListOptions: listOptions,
|
ListOptions: listOptions,
|
||||||
}
|
}
|
||||||
|
|
||||||
feeds, count, err := activities_model.GetFeeds(ctx, opts)
|
feeds, count, err := feed_service.GetFeeds(ctx, opts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.Error(http.StatusInternalServerError, "GetFeeds", err)
|
ctx.Error(http.StatusInternalServerError, "GetFeeds", err)
|
||||||
return
|
return
|
||||||
|
@ -22,6 +22,7 @@ import (
|
|||||||
"code.gitea.io/gitea/routers/api/v1/utils"
|
"code.gitea.io/gitea/routers/api/v1/utils"
|
||||||
"code.gitea.io/gitea/services/context"
|
"code.gitea.io/gitea/services/context"
|
||||||
"code.gitea.io/gitea/services/convert"
|
"code.gitea.io/gitea/services/convert"
|
||||||
|
feed_service "code.gitea.io/gitea/services/feed"
|
||||||
org_service "code.gitea.io/gitea/services/org"
|
org_service "code.gitea.io/gitea/services/org"
|
||||||
repo_service "code.gitea.io/gitea/services/repository"
|
repo_service "code.gitea.io/gitea/services/repository"
|
||||||
)
|
)
|
||||||
@ -882,7 +883,7 @@ func ListTeamActivityFeeds(ctx *context.APIContext) {
|
|||||||
ListOptions: listOptions,
|
ListOptions: listOptions,
|
||||||
}
|
}
|
||||||
|
|
||||||
feeds, count, err := activities_model.GetFeeds(ctx, opts)
|
feeds, count, err := feed_service.GetFeeds(ctx, opts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.Error(http.StatusInternalServerError, "GetFeeds", err)
|
ctx.Error(http.StatusInternalServerError, "GetFeeds", err)
|
||||||
return
|
return
|
||||||
|
@ -34,6 +34,7 @@ import (
|
|||||||
actions_service "code.gitea.io/gitea/services/actions"
|
actions_service "code.gitea.io/gitea/services/actions"
|
||||||
"code.gitea.io/gitea/services/context"
|
"code.gitea.io/gitea/services/context"
|
||||||
"code.gitea.io/gitea/services/convert"
|
"code.gitea.io/gitea/services/convert"
|
||||||
|
feed_service "code.gitea.io/gitea/services/feed"
|
||||||
"code.gitea.io/gitea/services/issue"
|
"code.gitea.io/gitea/services/issue"
|
||||||
repo_service "code.gitea.io/gitea/services/repository"
|
repo_service "code.gitea.io/gitea/services/repository"
|
||||||
)
|
)
|
||||||
@ -1313,7 +1314,7 @@ func ListRepoActivityFeeds(ctx *context.APIContext) {
|
|||||||
ListOptions: listOptions,
|
ListOptions: listOptions,
|
||||||
}
|
}
|
||||||
|
|
||||||
feeds, count, err := activities_model.GetFeeds(ctx, opts)
|
feeds, count, err := feed_service.GetFeeds(ctx, opts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.Error(http.StatusInternalServerError, "GetFeeds", err)
|
ctx.Error(http.StatusInternalServerError, "GetFeeds", err)
|
||||||
return
|
return
|
||||||
|
@ -13,6 +13,7 @@ import (
|
|||||||
"code.gitea.io/gitea/routers/api/v1/utils"
|
"code.gitea.io/gitea/routers/api/v1/utils"
|
||||||
"code.gitea.io/gitea/services/context"
|
"code.gitea.io/gitea/services/context"
|
||||||
"code.gitea.io/gitea/services/convert"
|
"code.gitea.io/gitea/services/convert"
|
||||||
|
feed_service "code.gitea.io/gitea/services/feed"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Search search users
|
// Search search users
|
||||||
@ -214,7 +215,7 @@ func ListUserActivityFeeds(ctx *context.APIContext) {
|
|||||||
ListOptions: listOptions,
|
ListOptions: listOptions,
|
||||||
}
|
}
|
||||||
|
|
||||||
feeds, count, err := activities_model.GetFeeds(ctx, opts)
|
feeds, count, err := feed_service.GetFeeds(ctx, opts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.Error(http.StatusInternalServerError, "GetFeeds", err)
|
ctx.Error(http.StatusInternalServerError, "GetFeeds", err)
|
||||||
return
|
return
|
||||||
|
@ -10,6 +10,7 @@ import (
|
|||||||
"code.gitea.io/gitea/models/renderhelper"
|
"code.gitea.io/gitea/models/renderhelper"
|
||||||
"code.gitea.io/gitea/modules/markup/markdown"
|
"code.gitea.io/gitea/modules/markup/markdown"
|
||||||
"code.gitea.io/gitea/services/context"
|
"code.gitea.io/gitea/services/context"
|
||||||
|
feed_service "code.gitea.io/gitea/services/feed"
|
||||||
|
|
||||||
"github.com/gorilla/feeds"
|
"github.com/gorilla/feeds"
|
||||||
)
|
)
|
||||||
@ -28,7 +29,7 @@ func ShowUserFeedAtom(ctx *context.Context) {
|
|||||||
func showUserFeed(ctx *context.Context, formatType string) {
|
func showUserFeed(ctx *context.Context, formatType string) {
|
||||||
includePrivate := ctx.IsSigned && (ctx.Doer.IsAdmin || ctx.Doer.ID == ctx.ContextUser.ID)
|
includePrivate := ctx.IsSigned && (ctx.Doer.IsAdmin || ctx.Doer.ID == ctx.ContextUser.ID)
|
||||||
|
|
||||||
actions, _, err := activities_model.GetFeeds(ctx, activities_model.GetFeedsOptions{
|
actions, _, err := feed_service.GetFeeds(ctx, activities_model.GetFeedsOptions{
|
||||||
RequestedUser: ctx.ContextUser,
|
RequestedUser: ctx.ContextUser,
|
||||||
Actor: ctx.Doer,
|
Actor: ctx.Doer,
|
||||||
IncludePrivate: includePrivate,
|
IncludePrivate: includePrivate,
|
||||||
|
@ -9,13 +9,14 @@ import (
|
|||||||
activities_model "code.gitea.io/gitea/models/activities"
|
activities_model "code.gitea.io/gitea/models/activities"
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
"code.gitea.io/gitea/services/context"
|
"code.gitea.io/gitea/services/context"
|
||||||
|
feed_service "code.gitea.io/gitea/services/feed"
|
||||||
|
|
||||||
"github.com/gorilla/feeds"
|
"github.com/gorilla/feeds"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ShowRepoFeed shows user activity on the repo as RSS / Atom feed
|
// ShowRepoFeed shows user activity on the repo as RSS / Atom feed
|
||||||
func ShowRepoFeed(ctx *context.Context, repo *repo_model.Repository, formatType string) {
|
func ShowRepoFeed(ctx *context.Context, repo *repo_model.Repository, formatType string) {
|
||||||
actions, _, err := activities_model.GetFeeds(ctx, activities_model.GetFeedsOptions{
|
actions, _, err := feed_service.GetFeeds(ctx, activities_model.GetFeedsOptions{
|
||||||
RequestedRepo: repo,
|
RequestedRepo: repo,
|
||||||
Actor: ctx.Doer,
|
Actor: ctx.Doer,
|
||||||
IncludePrivate: true,
|
IncludePrivate: true,
|
||||||
|
@ -33,6 +33,7 @@ import (
|
|||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
"code.gitea.io/gitea/routers/web/feed"
|
"code.gitea.io/gitea/routers/web/feed"
|
||||||
"code.gitea.io/gitea/services/context"
|
"code.gitea.io/gitea/services/context"
|
||||||
|
feed_service "code.gitea.io/gitea/services/feed"
|
||||||
issue_service "code.gitea.io/gitea/services/issue"
|
issue_service "code.gitea.io/gitea/services/issue"
|
||||||
pull_service "code.gitea.io/gitea/services/pull"
|
pull_service "code.gitea.io/gitea/services/pull"
|
||||||
|
|
||||||
@ -113,7 +114,7 @@ func Dashboard(ctx *context.Context) {
|
|||||||
ctx.Data["HeatmapTotalContributions"] = activities_model.GetTotalContributionsInHeatmap(data)
|
ctx.Data["HeatmapTotalContributions"] = activities_model.GetTotalContributionsInHeatmap(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
feeds, count, err := activities_model.GetFeeds(ctx, activities_model.GetFeedsOptions{
|
feeds, count, err := feed_service.GetFeeds(ctx, activities_model.GetFeedsOptions{
|
||||||
RequestedUser: ctxUser,
|
RequestedUser: ctxUser,
|
||||||
RequestedTeam: ctx.Org.Team,
|
RequestedTeam: ctx.Org.Team,
|
||||||
Actor: ctx.Doer,
|
Actor: ctx.Doer,
|
||||||
|
@ -26,6 +26,7 @@ import (
|
|||||||
"code.gitea.io/gitea/routers/web/org"
|
"code.gitea.io/gitea/routers/web/org"
|
||||||
shared_user "code.gitea.io/gitea/routers/web/shared/user"
|
shared_user "code.gitea.io/gitea/routers/web/shared/user"
|
||||||
"code.gitea.io/gitea/services/context"
|
"code.gitea.io/gitea/services/context"
|
||||||
|
feed_service "code.gitea.io/gitea/services/feed"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -167,7 +168,7 @@ func prepareUserProfileTabData(ctx *context.Context, showPrivate bool, profileDb
|
|||||||
case "activity":
|
case "activity":
|
||||||
date := ctx.FormString("date")
|
date := ctx.FormString("date")
|
||||||
pagingNum = setting.UI.FeedPagingNum
|
pagingNum = setting.UI.FeedPagingNum
|
||||||
items, count, err := activities_model.GetFeeds(ctx, activities_model.GetFeedsOptions{
|
items, count, err := feed_service.GetFeeds(ctx, activities_model.GetFeedsOptions{
|
||||||
RequestedUser: ctx.ContextUser,
|
RequestedUser: ctx.ContextUser,
|
||||||
Actor: ctx.Doer,
|
Actor: ctx.Doer,
|
||||||
IncludePrivate: showPrivate,
|
IncludePrivate: showPrivate,
|
||||||
|
15
services/feed/feed.go
Normal file
15
services/feed/feed.go
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
// Copyright 2024 The Gitea Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package feed
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
activities_model "code.gitea.io/gitea/models/activities"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GetFeeds returns actions according to the provided options
|
||||||
|
func GetFeeds(ctx context.Context, opts activities_model.GetFeedsOptions) (activities_model.ActionList, int64, error) {
|
||||||
|
return activities_model.GetFeeds(ctx, opts)
|
||||||
|
}
|
165
services/feed/feed_test.go
Normal file
165
services/feed/feed_test.go
Normal file
@ -0,0 +1,165 @@
|
|||||||
|
// Copyright 2024 The Gitea Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package feed
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
activities_model "code.gitea.io/gitea/models/activities"
|
||||||
|
"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"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestGetFeeds(t *testing.T) {
|
||||||
|
// test with an individual user
|
||||||
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
||||||
|
|
||||||
|
actions, count, err := GetFeeds(db.DefaultContext, activities_model.GetFeedsOptions{
|
||||||
|
RequestedUser: user,
|
||||||
|
Actor: user,
|
||||||
|
IncludePrivate: true,
|
||||||
|
OnlyPerformedBy: false,
|
||||||
|
IncludeDeleted: true,
|
||||||
|
})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
if assert.Len(t, actions, 1) {
|
||||||
|
assert.EqualValues(t, 1, actions[0].ID)
|
||||||
|
assert.EqualValues(t, user.ID, actions[0].UserID)
|
||||||
|
}
|
||||||
|
assert.Equal(t, int64(1), count)
|
||||||
|
|
||||||
|
actions, count, err = GetFeeds(db.DefaultContext, activities_model.GetFeedsOptions{
|
||||||
|
RequestedUser: user,
|
||||||
|
Actor: user,
|
||||||
|
IncludePrivate: false,
|
||||||
|
OnlyPerformedBy: false,
|
||||||
|
})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Len(t, actions, 0)
|
||||||
|
assert.Equal(t, int64(0), count)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetFeedsForRepos(t *testing.T) {
|
||||||
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
||||||
|
privRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2})
|
||||||
|
pubRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 8})
|
||||||
|
|
||||||
|
// private repo & no login
|
||||||
|
actions, count, err := GetFeeds(db.DefaultContext, activities_model.GetFeedsOptions{
|
||||||
|
RequestedRepo: privRepo,
|
||||||
|
IncludePrivate: true,
|
||||||
|
})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Len(t, actions, 0)
|
||||||
|
assert.Equal(t, int64(0), count)
|
||||||
|
|
||||||
|
// public repo & no login
|
||||||
|
actions, count, err = GetFeeds(db.DefaultContext, activities_model.GetFeedsOptions{
|
||||||
|
RequestedRepo: pubRepo,
|
||||||
|
IncludePrivate: true,
|
||||||
|
})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Len(t, actions, 1)
|
||||||
|
assert.Equal(t, int64(1), count)
|
||||||
|
|
||||||
|
// private repo and login
|
||||||
|
actions, count, err = GetFeeds(db.DefaultContext, activities_model.GetFeedsOptions{
|
||||||
|
RequestedRepo: privRepo,
|
||||||
|
IncludePrivate: true,
|
||||||
|
Actor: user,
|
||||||
|
})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Len(t, actions, 1)
|
||||||
|
assert.Equal(t, int64(1), count)
|
||||||
|
|
||||||
|
// public repo & login
|
||||||
|
actions, count, err = GetFeeds(db.DefaultContext, activities_model.GetFeedsOptions{
|
||||||
|
RequestedRepo: pubRepo,
|
||||||
|
IncludePrivate: true,
|
||||||
|
Actor: user,
|
||||||
|
})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Len(t, actions, 1)
|
||||||
|
assert.Equal(t, int64(1), count)
|
||||||
|
}
|
||||||
|
|
||||||
|
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 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
||||||
|
|
||||||
|
actions, count, err := GetFeeds(db.DefaultContext, activities_model.GetFeedsOptions{
|
||||||
|
RequestedUser: org,
|
||||||
|
Actor: user,
|
||||||
|
IncludePrivate: true,
|
||||||
|
OnlyPerformedBy: false,
|
||||||
|
IncludeDeleted: true,
|
||||||
|
})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Len(t, actions, 1)
|
||||||
|
if assert.Len(t, actions, 1) {
|
||||||
|
assert.EqualValues(t, 2, actions[0].ID)
|
||||||
|
assert.EqualValues(t, org.ID, actions[0].UserID)
|
||||||
|
}
|
||||||
|
assert.Equal(t, int64(1), count)
|
||||||
|
|
||||||
|
actions, count, err = GetFeeds(db.DefaultContext, activities_model.GetFeedsOptions{
|
||||||
|
RequestedUser: org,
|
||||||
|
Actor: user,
|
||||||
|
IncludePrivate: false,
|
||||||
|
OnlyPerformedBy: false,
|
||||||
|
IncludeDeleted: true,
|
||||||
|
})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Len(t, actions, 0)
|
||||||
|
assert.Equal(t, int64(0), count)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetFeedsCorrupted(t *testing.T) {
|
||||||
|
// Now we will not check for corrupted data in the feeds
|
||||||
|
// users should run doctor to fix their data
|
||||||
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1})
|
||||||
|
unittest.AssertExistsAndLoadBean(t, &activities_model.Action{
|
||||||
|
ID: 8,
|
||||||
|
RepoID: 1700,
|
||||||
|
})
|
||||||
|
|
||||||
|
actions, count, err := GetFeeds(db.DefaultContext, activities_model.GetFeedsOptions{
|
||||||
|
RequestedUser: user,
|
||||||
|
Actor: user,
|
||||||
|
IncludePrivate: true,
|
||||||
|
})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Len(t, actions, 1)
|
||||||
|
assert.Equal(t, int64(1), count)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRepoActions(t *testing.T) {
|
||||||
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
||||||
|
_ = db.TruncateBeans(db.DefaultContext, &activities_model.Action{})
|
||||||
|
for i := 0; i < 3; i++ {
|
||||||
|
_ = db.Insert(db.DefaultContext, &activities_model.Action{
|
||||||
|
UserID: 2 + int64(i),
|
||||||
|
ActUserID: 2,
|
||||||
|
RepoID: repo.ID,
|
||||||
|
OpType: activities_model.ActionCommentIssue,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
count, _ := db.Count[activities_model.Action](db.DefaultContext, &db.ListOptions{})
|
||||||
|
assert.EqualValues(t, 3, count)
|
||||||
|
actions, _, err := GetFeeds(db.DefaultContext, activities_model.GetFeedsOptions{
|
||||||
|
RequestedRepo: repo,
|
||||||
|
})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Len(t, actions, 1)
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user