Skip to content

Commit 4e5ee2b

Browse files
ethantkoeniglunny
authored andcommitted
Fix user profile activity feed (#1848)
* Fix user profile activity feed * gofmt, and avoid overlapping database connections
1 parent 5ca6867 commit 4e5ee2b

File tree

5 files changed

+74
-48
lines changed

5 files changed

+74
-48
lines changed

models/action.go

Lines changed: 28 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -672,33 +672,39 @@ func MergePullRequestAction(actUser *User, repo *Repository, pull *Issue) error
672672
return mergePullRequestAction(x, actUser, repo, pull)
673673
}
674674

675-
// GetFeeds returns action list of given user in given context.
676-
// actorID is the user who's requesting, ctxUserID is the user/org that is requested.
677-
// actorID can be -1 when isProfile is true or to skip the permission check.
678-
func GetFeeds(ctxUser *User, actorID, offset int64, isProfile bool) ([]*Action, error) {
679-
actions := make([]*Action, 0, 20)
680-
sess := x.
681-
Limit(20, int(offset)).
682-
Desc("id").
683-
Where("user_id = ?", ctxUser.ID)
684-
if isProfile {
685-
sess.
686-
And("is_private = ?", false).
687-
And("act_user_id = ?", ctxUser.ID)
688-
} else if actorID != -1 && ctxUser.IsOrganization() {
689-
env, err := ctxUser.AccessibleReposEnv(actorID)
675+
// GetFeedsOptions options for retrieving feeds
676+
type GetFeedsOptions struct {
677+
RequestedUser *User
678+
RequestingUserID int64
679+
IncludePrivate bool // include private actions
680+
OnlyPerformedBy bool // only actions performed by requested user
681+
}
682+
683+
// GetFeeds returns actions according to the provided options
684+
func GetFeeds(opts GetFeedsOptions) ([]*Action, error) {
685+
var repoIDs []int64
686+
if opts.RequestedUser.IsOrganization() {
687+
env, err := opts.RequestedUser.AccessibleReposEnv(opts.RequestingUserID)
690688
if err != nil {
691689
return nil, fmt.Errorf("AccessibleReposEnv: %v", err)
692690
}
693-
repoIDs, err := env.RepoIDs(1, ctxUser.NumRepos)
694-
if err != nil {
691+
if repoIDs, err = env.RepoIDs(1, opts.RequestedUser.NumRepos); err != nil {
695692
return nil, fmt.Errorf("GetUserRepositories: %v", err)
696693
}
697-
if len(repoIDs) > 0 {
698-
sess.In("repo_id", repoIDs)
699-
}
700694
}
701695

702-
err := sess.Find(&actions)
703-
return actions, err
696+
actions := make([]*Action, 0, 20)
697+
sess := x.Limit(20).
698+
Desc("id").
699+
Where("user_id = ?", opts.RequestedUser.ID)
700+
if opts.OnlyPerformedBy {
701+
sess.And("act_user_id = ?", opts.RequestedUser.ID)
702+
}
703+
if !opts.IncludePrivate {
704+
sess.And("is_private = ?", false)
705+
}
706+
if opts.RequestedUser.IsOrganization() {
707+
sess.In("repo_id", repoIDs)
708+
}
709+
return actions, sess.Find(&actions)
704710
}

models/action_test.go

Lines changed: 33 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -305,29 +305,50 @@ func TestGetFeeds(t *testing.T) {
305305
assert.NoError(t, PrepareTestDatabase())
306306
user := AssertExistsAndLoadBean(t, &User{ID: 2}).(*User)
307307

308-
actions, err := GetFeeds(user, user.ID, 0, false)
308+
actions, err := GetFeeds(GetFeedsOptions{
309+
RequestedUser: user,
310+
RequestingUserID: user.ID,
311+
IncludePrivate: true,
312+
OnlyPerformedBy: false,
313+
})
309314
assert.NoError(t, err)
310315
assert.Len(t, actions, 1)
311-
assert.Equal(t, int64(1), actions[0].ID)
312-
assert.Equal(t, user.ID, actions[0].UserID)
313-
314-
actions, err = GetFeeds(user, user.ID, 0, true)
316+
assert.EqualValues(t, 1, actions[0].ID)
317+
assert.EqualValues(t, user.ID, actions[0].UserID)
318+
319+
actions, err = GetFeeds(GetFeedsOptions{
320+
RequestedUser: user,
321+
RequestingUserID: user.ID,
322+
IncludePrivate: false,
323+
OnlyPerformedBy: false,
324+
})
315325
assert.NoError(t, err)
316326
assert.Len(t, actions, 0)
317327
}
318328

319329
func TestGetFeeds2(t *testing.T) {
320330
// test with an organization user
321331
assert.NoError(t, PrepareTestDatabase())
322-
user := AssertExistsAndLoadBean(t, &User{ID: 3}).(*User)
323-
324-
actions, err := GetFeeds(user, user.ID, 0, false)
332+
org := AssertExistsAndLoadBean(t, &User{ID: 3}).(*User)
333+
userID := AssertExistsAndLoadBean(t, &OrgUser{OrgID: org.ID, IsOwner: true}).(*OrgUser).UID
334+
335+
actions, err := GetFeeds(GetFeedsOptions{
336+
RequestedUser: org,
337+
RequestingUserID: userID,
338+
IncludePrivate: true,
339+
OnlyPerformedBy: false,
340+
})
325341
assert.NoError(t, err)
326342
assert.Len(t, actions, 1)
327-
assert.Equal(t, int64(2), actions[0].ID)
328-
assert.Equal(t, user.ID, actions[0].UserID)
329-
330-
actions, err = GetFeeds(user, user.ID, 0, true)
343+
assert.EqualValues(t, 2, actions[0].ID)
344+
assert.EqualValues(t, org.ID, actions[0].UserID)
345+
346+
actions, err = GetFeeds(GetFeedsOptions{
347+
RequestedUser: org,
348+
RequestingUserID: userID,
349+
IncludePrivate: false,
350+
OnlyPerformedBy: false,
351+
})
331352
assert.NoError(t, err)
332353
assert.Len(t, actions, 0)
333354
}

models/fixtures/action.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
id: 2
1111
user_id: 3
1212
op_type: 2 # rename repo
13-
act_user_id: 3
13+
act_user_id: 2
1414
repo_id: 3
1515
is_private: true
1616
content: oldRepoName

routers/user/home.go

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -53,19 +53,20 @@ func getDashboardContextUser(ctx *context.Context) *models.User {
5353
return ctxUser
5454
}
5555

56-
// retrieveFeeds loads feeds from database by given context user.
57-
// The user could be organization so it is not always the logged in user,
58-
// which is why we have to explicitly pass the context user ID.
59-
func retrieveFeeds(ctx *context.Context, ctxUser *models.User, userID, offset int64, isProfile bool) {
60-
actions, err := models.GetFeeds(ctxUser, userID, offset, isProfile)
56+
// retrieveFeeds loads feeds for the specified user
57+
func retrieveFeeds(ctx *context.Context, user *models.User, includePrivate, isProfile bool) {
58+
actions, err := models.GetFeeds(models.GetFeedsOptions{
59+
RequestedUser: user,
60+
RequestingUserID: ctx.User.ID,
61+
IncludePrivate: includePrivate,
62+
OnlyPerformedBy: isProfile,
63+
})
6164
if err != nil {
6265
ctx.Handle(500, "GetFeeds", err)
6366
return
6467
}
6568

66-
// Check access of private repositories.
67-
feeds := make([]*models.Action, 0, len(actions))
68-
userCache := map[int64]*models.User{ctxUser.ID: ctxUser}
69+
userCache := map[int64]*models.User{user.ID: user}
6970
repoCache := map[int64]*models.Repository{}
7071
for _, act := range actions {
7172
// Cache results to reduce queries.
@@ -108,10 +109,8 @@ func retrieveFeeds(ctx *context.Context, ctxUser *models.User, userID, offset in
108109
}
109110
}
110111
repo.Owner = repoOwner
111-
112-
feeds = append(feeds, act)
113112
}
114-
ctx.Data["Feeds"] = feeds
113+
ctx.Data["Feeds"] = actions
115114
}
116115

117116
// Dashboard render the dashborad page
@@ -180,7 +179,7 @@ func Dashboard(ctx *context.Context) {
180179
ctx.Data["MirrorCount"] = len(mirrors)
181180
ctx.Data["Mirrors"] = mirrors
182181

183-
retrieveFeeds(ctx, ctxUser, ctx.User.ID, 0, false)
182+
retrieveFeeds(ctx, ctxUser, true, false)
184183
if ctx.Written() {
185184
return
186185
}

routers/user/profile.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ func Profile(ctx *context.Context) {
138138
ctx.Data["Keyword"] = keyword
139139
switch tab {
140140
case "activity":
141-
retrieveFeeds(ctx, ctxUser, -1, 0, !showPrivate)
141+
retrieveFeeds(ctx, ctxUser, showPrivate, true)
142142
if ctx.Written() {
143143
return
144144
}

0 commit comments

Comments
 (0)