Browse Source

Fix activity feed (#1779)

* Fix activity feed

Preserve actions after user/repo name change

* Add missing comment

* Fix migration, and remove fields completely

* Tests
Ethan Koenig 1 year ago
parent
commit
0c332f0480

+ 12 - 10
integrations/mysql.ini

@@ -6,7 +6,7 @@ DB_TYPE  = mysql
6 6
 HOST     = 127.0.0.1:3306
7 7
 NAME     = testgitea
8 8
 USER     = root
9
-PASSWD   =
9
+PASSWD   = 
10 10
 SSL_MODE = disable
11 11
 PATH     = data/gitea.db
12 12
 
@@ -26,14 +26,14 @@ OFFLINE_MODE     = false
26 26
 ENABLED = false
27 27
 
28 28
 [service]
29
-REGISTER_EMAIL_CONFIRM     = false
30
-ENABLE_NOTIFY_MAIL         = false
31
-DISABLE_REGISTRATION       = false
32
-ENABLE_CAPTCHA             = false
33
-REQUIRE_SIGNIN_VIEW        = false
34
-DEFAULT_KEEP_EMAIL_PRIVATE = false
29
+REGISTER_EMAIL_CONFIRM            = false
30
+ENABLE_NOTIFY_MAIL                = false
31
+DISABLE_REGISTRATION              = false
32
+ENABLE_CAPTCHA                    = false
33
+REQUIRE_SIGNIN_VIEW               = false
34
+DEFAULT_KEEP_EMAIL_PRIVATE        = false
35 35
 DEFAULT_ALLOW_CREATE_ORGANIZATION = true
36
-NO_REPLY_ADDRESS           = noreply.example.org
36
+NO_REPLY_ADDRESS                  = noreply.example.org
37 37
 
38 38
 [picture]
39 39
 DISABLE_GRAVATAR        = false
@@ -53,5 +53,7 @@ LEVEL = Warn
53 53
 LEVEL = Info
54 54
 
55 55
 [security]
56
-INSTALL_LOCK = true
57
-SECRET_KEY   = 9pCviYTWSb
56
+INSTALL_LOCK   = true
57
+SECRET_KEY     = 9pCviYTWSb
58
+INTERNAL_TOKEN = eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYmYiOjE0OTU1NTE2MTh9.hhSVGOANkaKk3vfCd2jDOIww4pUk0xtg9JRde5UogyQ
59
+

+ 83 - 61
models/action.go

@@ -70,20 +70,18 @@ func init() {
70 70
 // repository. It implemented interface base.Actioner so that can be
71 71
 // used in template render.
72 72
 type Action struct {
73
-	ID           int64 `xorm:"pk autoincr"`
74
-	UserID       int64 `xorm:"INDEX"` // Receiver user id.
75
-	OpType       ActionType
76
-	ActUserID    int64  `xorm:"INDEX"` // Action user id.
77
-	ActUserName  string // Action user name.
78
-	ActAvatar    string `xorm:"-"`
79
-	RepoID       int64  `xorm:"INDEX"`
80
-	RepoUserName string
81
-	RepoName     string
82
-	RefName      string
83
-	IsPrivate    bool      `xorm:"INDEX NOT NULL DEFAULT false"`
84
-	Content      string    `xorm:"TEXT"`
85
-	Created      time.Time `xorm:"-"`
86
-	CreatedUnix  int64     `xorm:"INDEX"`
73
+	ID          int64 `xorm:"pk autoincr"`
74
+	UserID      int64 `xorm:"INDEX"` // Receiver user id.
75
+	OpType      ActionType
76
+	ActUserID   int64       `xorm:"INDEX"` // Action user id.
77
+	ActUser     *User       `xorm:"-"`
78
+	RepoID      int64       `xorm:"INDEX"`
79
+	Repo        *Repository `xorm:"-"`
80
+	RefName     string
81
+	IsPrivate   bool      `xorm:"INDEX NOT NULL DEFAULT false"`
82
+	Content     string    `xorm:"TEXT"`
83
+	Created     time.Time `xorm:"-"`
84
+	CreatedUnix int64     `xorm:"INDEX"`
87 85
 }
88 86
 
89 87
 // BeforeInsert will be invoked by XORM before inserting a record
@@ -106,42 +104,71 @@ func (a *Action) GetOpType() int {
106 104
 	return int(a.OpType)
107 105
 }
108 106
 
107
+func (a *Action) loadActUser() {
108
+	if a.ActUser != nil {
109
+		return
110
+	}
111
+	var err error
112
+	a.ActUser, err = GetUserByID(a.ActUserID)
113
+	if err == nil {
114
+		return
115
+	} else if IsErrUserNotExist(err) {
116
+		a.ActUser = NewGhostUser()
117
+	} else {
118
+		log.Error(4, "GetUserByID(%d): %v", a.ActUserID, err)
119
+	}
120
+}
121
+
122
+func (a *Action) loadRepo() {
123
+	if a.ActUser != nil {
124
+		return
125
+	}
126
+	var err error
127
+	a.Repo, err = GetRepositoryByID(a.RepoID)
128
+	if err != nil {
129
+		log.Error(4, "GetRepositoryByID(%d): %v", a.RepoID, err)
130
+	}
131
+}
132
+
109 133
 // GetActUserName gets the action's user name.
110 134
 func (a *Action) GetActUserName() string {
111
-	return a.ActUserName
135
+	a.loadActUser()
136
+	return a.ActUser.Name
112 137
 }
113 138
 
114 139
 // ShortActUserName gets the action's user name trimmed to max 20
115 140
 // chars.
116 141
 func (a *Action) ShortActUserName() string {
117
-	return base.EllipsisString(a.ActUserName, 20)
142
+	return base.EllipsisString(a.GetActUserName(), 20)
118 143
 }
119 144
 
120 145
 // GetRepoUserName returns the name of the action repository owner.
121 146
 func (a *Action) GetRepoUserName() string {
122
-	return a.RepoUserName
147
+	a.loadRepo()
148
+	return a.Repo.MustOwner().Name
123 149
 }
124 150
 
125 151
 // ShortRepoUserName returns the name of the action repository owner
126 152
 // trimmed to max 20 chars.
127 153
 func (a *Action) ShortRepoUserName() string {
128
-	return base.EllipsisString(a.RepoUserName, 20)
154
+	return base.EllipsisString(a.GetRepoUserName(), 20)
129 155
 }
130 156
 
131 157
 // GetRepoName returns the name of the action repository.
132 158
 func (a *Action) GetRepoName() string {
133
-	return a.RepoName
159
+	a.loadRepo()
160
+	return a.Repo.Name
134 161
 }
135 162
 
136 163
 // ShortRepoName returns the name of the action repository
137 164
 // trimmed to max 33 chars.
138 165
 func (a *Action) ShortRepoName() string {
139
-	return base.EllipsisString(a.RepoName, 33)
166
+	return base.EllipsisString(a.GetRepoName(), 33)
140 167
 }
141 168
 
142 169
 // GetRepoPath returns the virtual path to the action repository.
143 170
 func (a *Action) GetRepoPath() string {
144
-	return path.Join(a.RepoUserName, a.RepoName)
171
+	return path.Join(a.GetRepoUserName(), a.GetRepoName())
145 172
 }
146 173
 
147 174
 // ShortRepoPath returns the virtual path to the action repository
@@ -205,13 +232,12 @@ func (a *Action) GetIssueContent() string {
205 232
 
206 233
 func newRepoAction(e Engine, u *User, repo *Repository) (err error) {
207 234
 	if err = notifyWatchers(e, &Action{
208
-		ActUserID:    u.ID,
209
-		ActUserName:  u.Name,
210
-		OpType:       ActionCreateRepo,
211
-		RepoID:       repo.ID,
212
-		RepoUserName: repo.Owner.Name,
213
-		RepoName:     repo.Name,
214
-		IsPrivate:    repo.IsPrivate,
235
+		ActUserID: u.ID,
236
+		ActUser:   u,
237
+		OpType:    ActionCreateRepo,
238
+		RepoID:    repo.ID,
239
+		Repo:      repo,
240
+		IsPrivate: repo.IsPrivate,
215 241
 	}); err != nil {
216 242
 		return fmt.Errorf("notify watchers '%d/%d': %v", u.ID, repo.ID, err)
217 243
 	}
@@ -227,14 +253,13 @@ func NewRepoAction(u *User, repo *Repository) (err error) {
227 253
 
228 254
 func renameRepoAction(e Engine, actUser *User, oldRepoName string, repo *Repository) (err error) {
229 255
 	if err = notifyWatchers(e, &Action{
230
-		ActUserID:    actUser.ID,
231
-		ActUserName:  actUser.Name,
232
-		OpType:       ActionRenameRepo,
233
-		RepoID:       repo.ID,
234
-		RepoUserName: repo.Owner.Name,
235
-		RepoName:     repo.Name,
236
-		IsPrivate:    repo.IsPrivate,
237
-		Content:      oldRepoName,
256
+		ActUserID: actUser.ID,
257
+		ActUser:   actUser,
258
+		OpType:    ActionRenameRepo,
259
+		RepoID:    repo.ID,
260
+		Repo:      repo,
261
+		IsPrivate: repo.IsPrivate,
262
+		Content:   oldRepoName,
238 263
 	}); err != nil {
239 264
 		return fmt.Errorf("notify watchers: %v", err)
240 265
 	}
@@ -521,15 +546,14 @@ func CommitRepoAction(opts CommitRepoActionOptions) error {
521 546
 
522 547
 	refName := git.RefEndName(opts.RefFullName)
523 548
 	if err = NotifyWatchers(&Action{
524
-		ActUserID:    pusher.ID,
525
-		ActUserName:  pusher.Name,
526
-		OpType:       opType,
527
-		Content:      string(data),
528
-		RepoID:       repo.ID,
529
-		RepoUserName: repo.MustOwner().Name,
530
-		RepoName:     repo.Name,
531
-		RefName:      refName,
532
-		IsPrivate:    repo.IsPrivate,
549
+		ActUserID: pusher.ID,
550
+		ActUser:   pusher,
551
+		OpType:    opType,
552
+		Content:   string(data),
553
+		RepoID:    repo.ID,
554
+		Repo:      repo,
555
+		RefName:   refName,
556
+		IsPrivate: repo.IsPrivate,
533 557
 	}); err != nil {
534 558
 		return fmt.Errorf("NotifyWatchers: %v", err)
535 559
 	}
@@ -598,14 +622,13 @@ func CommitRepoAction(opts CommitRepoActionOptions) error {
598 622
 
599 623
 func transferRepoAction(e Engine, doer, oldOwner *User, repo *Repository) (err error) {
600 624
 	if err = notifyWatchers(e, &Action{
601
-		ActUserID:    doer.ID,
602
-		ActUserName:  doer.Name,
603
-		OpType:       ActionTransferRepo,
604
-		RepoID:       repo.ID,
605
-		RepoUserName: repo.Owner.Name,
606
-		RepoName:     repo.Name,
607
-		IsPrivate:    repo.IsPrivate,
608
-		Content:      path.Join(oldOwner.Name, repo.Name),
625
+		ActUserID: doer.ID,
626
+		ActUser:   doer,
627
+		OpType:    ActionTransferRepo,
628
+		RepoID:    repo.ID,
629
+		Repo:      repo,
630
+		IsPrivate: repo.IsPrivate,
631
+		Content:   path.Join(oldOwner.Name, repo.Name),
609 632
 	}); err != nil {
610 633
 		return fmt.Errorf("notifyWatchers: %v", err)
611 634
 	}
@@ -628,14 +651,13 @@ func TransferRepoAction(doer, oldOwner *User, repo *Repository) error {
628 651
 
629 652
 func mergePullRequestAction(e Engine, doer *User, repo *Repository, issue *Issue) error {
630 653
 	return notifyWatchers(e, &Action{
631
-		ActUserID:    doer.ID,
632
-		ActUserName:  doer.Name,
633
-		OpType:       ActionMergePullRequest,
634
-		Content:      fmt.Sprintf("%d|%s", issue.Index, issue.Title),
635
-		RepoID:       repo.ID,
636
-		RepoUserName: repo.Owner.Name,
637
-		RepoName:     repo.Name,
638
-		IsPrivate:    repo.IsPrivate,
654
+		ActUserID: doer.ID,
655
+		ActUser:   doer,
656
+		OpType:    ActionMergePullRequest,
657
+		Content:   fmt.Sprintf("%d|%s", issue.Index, issue.Title),
658
+		RepoID:    repo.ID,
659
+		Repo:      repo,
660
+		IsPrivate: repo.IsPrivate,
639 661
 	})
640 662
 }
641 663
 

+ 44 - 48
models/action_test.go

@@ -1,6 +1,7 @@
1 1
 package models
2 2
 
3 3
 import (
4
+	"path"
4 5
 	"strings"
5 6
 	"testing"
6 7
 
@@ -10,22 +11,21 @@ import (
10 11
 )
11 12
 
12 13
 func TestAction_GetRepoPath(t *testing.T) {
13
-	action := &Action{
14
-		RepoUserName: "username",
15
-		RepoName:     "reponame",
16
-	}
17
-	assert.Equal(t, "username/reponame", action.GetRepoPath())
14
+	assert.NoError(t, PrepareTestDatabase())
15
+	repo := AssertExistsAndLoadBean(t, &Repository{}).(*Repository)
16
+	owner := AssertExistsAndLoadBean(t, &User{ID: repo.OwnerID}).(*User)
17
+	action := &Action{RepoID: repo.ID}
18
+	assert.Equal(t, path.Join(owner.Name, repo.Name), action.GetRepoPath())
18 19
 }
19 20
 
20 21
 func TestAction_GetRepoLink(t *testing.T) {
21
-	action := &Action{
22
-		RepoUserName: "username",
23
-		RepoName:     "reponame",
24
-	}
22
+	assert.NoError(t, PrepareTestDatabase())
23
+	repo := AssertExistsAndLoadBean(t, &Repository{}).(*Repository)
24
+	owner := AssertExistsAndLoadBean(t, &User{ID: repo.OwnerID}).(*User)
25
+	action := &Action{RepoID: repo.ID}
25 26
 	setting.AppSubURL = "/suburl/"
26
-	assert.Equal(t, "/suburl/username/reponame", action.GetRepoLink())
27
-	setting.AppSubURL = ""
28
-	assert.Equal(t, "/username/reponame", action.GetRepoLink())
27
+	expected := path.Join(setting.AppSubURL, owner.Name, repo.Name)
28
+	assert.Equal(t, expected, action.GetRepoLink())
29 29
 }
30 30
 
31 31
 func TestNewRepoAction(t *testing.T) {
@@ -36,13 +36,12 @@ func TestNewRepoAction(t *testing.T) {
36 36
 	repo.Owner = user
37 37
 
38 38
 	actionBean := &Action{
39
-		OpType:       ActionCreateRepo,
40
-		ActUserID:    user.ID,
41
-		RepoID:       repo.ID,
42
-		ActUserName:  user.Name,
43
-		RepoName:     repo.Name,
44
-		RepoUserName: repo.Owner.Name,
45
-		IsPrivate:    repo.IsPrivate,
39
+		OpType:    ActionCreateRepo,
40
+		ActUserID: user.ID,
41
+		RepoID:    repo.ID,
42
+		ActUser:   user,
43
+		Repo:      repo,
44
+		IsPrivate: repo.IsPrivate,
46 45
 	}
47 46
 
48 47
 	AssertNotExistsBean(t, actionBean)
@@ -64,14 +63,13 @@ func TestRenameRepoAction(t *testing.T) {
64 63
 	repo.LowerName = strings.ToLower(newRepoName)
65 64
 
66 65
 	actionBean := &Action{
67
-		OpType:       ActionRenameRepo,
68
-		ActUserID:    user.ID,
69
-		ActUserName:  user.Name,
70
-		RepoID:       repo.ID,
71
-		RepoName:     repo.Name,
72
-		RepoUserName: repo.Owner.Name,
73
-		IsPrivate:    repo.IsPrivate,
74
-		Content:      oldRepoName,
66
+		OpType:    ActionRenameRepo,
67
+		ActUserID: user.ID,
68
+		ActUser:   user,
69
+		RepoID:    repo.ID,
70
+		Repo:      repo,
71
+		IsPrivate: repo.IsPrivate,
72
+		Content:   oldRepoName,
75 73
 	}
76 74
 	AssertNotExistsBean(t, actionBean)
77 75
 	assert.NoError(t, RenameRepoAction(user, oldRepoName, repo))
@@ -232,13 +230,13 @@ func TestCommitRepoAction(t *testing.T) {
232 230
 	pushCommits.Len = len(pushCommits.Commits)
233 231
 
234 232
 	actionBean := &Action{
235
-		OpType:      ActionCommitRepo,
236
-		ActUserID:   user.ID,
237
-		ActUserName: user.Name,
238
-		RepoID:      repo.ID,
239
-		RepoName:    repo.Name,
240
-		RefName:     "refName",
241
-		IsPrivate:   repo.IsPrivate,
233
+		OpType:    ActionCommitRepo,
234
+		ActUserID: user.ID,
235
+		ActUser:   user,
236
+		RepoID:    repo.ID,
237
+		Repo:      repo,
238
+		RefName:   "refName",
239
+		IsPrivate: repo.IsPrivate,
242 240
 	}
243 241
 	AssertNotExistsBean(t, actionBean)
244 242
 	assert.NoError(t, CommitRepoAction(CommitRepoActionOptions{
@@ -265,13 +263,12 @@ func TestTransferRepoAction(t *testing.T) {
265 263
 	repo.Owner = user4
266 264
 
267 265
 	actionBean := &Action{
268
-		OpType:       ActionTransferRepo,
269
-		ActUserID:    user2.ID,
270
-		ActUserName:  user2.Name,
271
-		RepoID:       repo.ID,
272
-		RepoName:     repo.Name,
273
-		RepoUserName: repo.Owner.Name,
274
-		IsPrivate:    repo.IsPrivate,
266
+		OpType:    ActionTransferRepo,
267
+		ActUserID: user2.ID,
268
+		ActUser:   user2,
269
+		RepoID:    repo.ID,
270
+		Repo:      repo,
271
+		IsPrivate: repo.IsPrivate,
275 272
 	}
276 273
 	AssertNotExistsBean(t, actionBean)
277 274
 	assert.NoError(t, TransferRepoAction(user2, user2, repo))
@@ -290,13 +287,12 @@ func TestMergePullRequestAction(t *testing.T) {
290 287
 	issue := AssertExistsAndLoadBean(t, &Issue{ID: 3, RepoID: repo.ID}).(*Issue)
291 288
 
292 289
 	actionBean := &Action{
293
-		OpType:       ActionMergePullRequest,
294
-		ActUserID:    user.ID,
295
-		ActUserName:  user.Name,
296
-		RepoID:       repo.ID,
297
-		RepoName:     repo.Name,
298
-		RepoUserName: repo.Owner.Name,
299
-		IsPrivate:    repo.IsPrivate,
290
+		OpType:    ActionMergePullRequest,
291
+		ActUserID: user.ID,
292
+		ActUser:   user,
293
+		RepoID:    repo.ID,
294
+		Repo:      repo,
295
+		IsPrivate: repo.IsPrivate,
300 296
 	}
301 297
 	AssertNotExistsBean(t, actionBean)
302 298
 	assert.NoError(t, MergePullRequestAction(user, repo, issue))

+ 0 - 6
models/consistency.go

@@ -162,11 +162,5 @@ func (team *Team) checkForConsistency(t *testing.T) {
162 162
 
163 163
 func (action *Action) checkForConsistency(t *testing.T) {
164 164
 	repo := AssertExistsAndLoadBean(t, &Repository{ID: action.RepoID}).(*Repository)
165
-	owner := AssertExistsAndLoadBean(t, &User{ID: repo.OwnerID}).(*User)
166
-	actor := AssertExistsAndLoadBean(t, &User{ID: action.ActUserID}).(*User)
167
-
168
-	assert.Equal(t, repo.Name, action.RepoName, "action: %+v", action)
169 165
 	assert.Equal(t, repo.IsPrivate, action.IsPrivate, "action: %+v", action)
170
-	assert.Equal(t, owner.Name, action.RepoUserName, "action: %+v", action)
171
-	assert.Equal(t, actor.Name, action.ActUserName, "action: %+v", action)
172 166
 }

+ 0 - 9
models/fixtures/action.yml

@@ -3,10 +3,7 @@
3 3
   user_id: 2
4 4
   op_type: 12 # close issue
5 5
   act_user_id: 2
6
-  act_user_name: user2
7 6
   repo_id: 2
8
-  repo_user_name: user2
9
-  repo_name: repo2
10 7
   is_private: true
11 8
 
12 9
 -
@@ -14,10 +11,7 @@
14 11
   user_id: 3
15 12
   op_type: 2 # rename repo
16 13
   act_user_id: 3
17
-  act_user_name: user3
18 14
   repo_id: 3
19
-  repo_user_name: user3
20
-  repo_name: repo3
21 15
   is_private: true
22 16
   content: oldRepoName
23 17
 
@@ -26,8 +20,5 @@
26 20
   user_id: 11
27 21
   op_type: 1 # create repo
28 22
   act_user_id: 11
29
-  act_user_name: user11
30 23
   repo_id: 9
31
-  repo_user_name: user11
32
-  repo_name: repo9
33 24
   is_private: false

+ 7 - 8
models/issue.go

@@ -918,14 +918,13 @@ func NewIssue(repo *Repository, issue *Issue, labelIDs []int64, uuids []string)
918 918
 	}
919 919
 
920 920
 	if err = NotifyWatchers(&Action{
921
-		ActUserID:    issue.Poster.ID,
922
-		ActUserName:  issue.Poster.Name,
923
-		OpType:       ActionCreateIssue,
924
-		Content:      fmt.Sprintf("%d|%s", issue.Index, issue.Title),
925
-		RepoID:       repo.ID,
926
-		RepoUserName: repo.Owner.Name,
927
-		RepoName:     repo.Name,
928
-		IsPrivate:    repo.IsPrivate,
921
+		ActUserID: issue.Poster.ID,
922
+		ActUser:   issue.Poster,
923
+		OpType:    ActionCreateIssue,
924
+		Content:   fmt.Sprintf("%d|%s", issue.Index, issue.Title),
925
+		RepoID:    repo.ID,
926
+		Repo:      repo,
927
+		IsPrivate: repo.IsPrivate,
929 928
 	}); err != nil {
930 929
 		log.Error(4, "NotifyWatchers: %v", err)
931 930
 	}

+ 6 - 7
models/issue_comment.go

@@ -329,13 +329,12 @@ func createComment(e *xorm.Session, opts *CreateCommentOptions) (_ *Comment, err
329 329
 	// Compose comment action, could be plain comment, close or reopen issue/pull request.
330 330
 	// This object will be used to notify watchers in the end of function.
331 331
 	act := &Action{
332
-		ActUserID:    opts.Doer.ID,
333
-		ActUserName:  opts.Doer.Name,
334
-		Content:      fmt.Sprintf("%d|%s", opts.Issue.Index, strings.Split(opts.Content, "\n")[0]),
335
-		RepoID:       opts.Repo.ID,
336
-		RepoUserName: opts.Repo.Owner.Name,
337
-		RepoName:     opts.Repo.Name,
338
-		IsPrivate:    opts.Repo.IsPrivate,
332
+		ActUserID: opts.Doer.ID,
333
+		ActUser:   opts.Doer,
334
+		Content:   fmt.Sprintf("%d|%s", opts.Issue.Index, strings.Split(opts.Content, "\n")[0]),
335
+		RepoID:    opts.Repo.ID,
336
+		Repo:      opts.Repo,
337
+		IsPrivate: opts.Repo.IsPrivate,
339 338
 	}
340 339
 
341 340
 	// Check comment type.

+ 2 - 0
models/migrations/migrations.go

@@ -114,6 +114,8 @@ var migrations = []Migration{
114 114
 	NewMigration("add field for login source synchronization", addLoginSourceSyncEnabledColumn),
115 115
 	// v32 -> v33
116 116
 	NewMigration("add units for team", addUnitsToRepoTeam),
117
+	// v33 -> v34
118
+	NewMigration("remove columns from action", removeActionColumns),
117 119
 }
118 120
 
119 121
 // Migrate database to current version

+ 44 - 0
models/migrations/v34.go

@@ -0,0 +1,44 @@
1
+// Copyright 2017 Gitea. All rights reserved.
2
+// Use of this source code is governed by a MIT-style
3
+// license that can be found in the LICENSE file.
4
+
5
+package migrations
6
+
7
+import (
8
+	"fmt"
9
+
10
+	"code.gitea.io/gitea/modules/log"
11
+	"code.gitea.io/gitea/modules/setting"
12
+
13
+	"github.com/go-xorm/xorm"
14
+)
15
+
16
+// ActionV34 describes the removed fields
17
+type ActionV34 struct {
18
+	ActUserName  string `xorm:"-"`
19
+	RepoUserName string `xorm:"-"`
20
+	RepoName     string `xorm:"-"`
21
+}
22
+
23
+// TableName will be invoked by XORM to customize the table name
24
+func (*ActionV34) TableName() string {
25
+	return "action"
26
+}
27
+
28
+func removeActionColumns(x *xorm.Engine) error {
29
+	switch {
30
+	case setting.UseSQLite3:
31
+		log.Warn("Unable to drop columns in SQLite")
32
+	case setting.UseMySQL, setting.UsePostgreSQL, setting.UseMSSQL, setting.UseTiDB:
33
+		if _, err := x.Exec("ALTER TABLE action DROP COLUMN act_user_name"); err != nil {
34
+			return fmt.Errorf("DROP COLUMN act_user_name: %v", err)
35
+		} else if _, err = x.Exec("ALTER TABLE action DROP COLUMN repo_user_name"); err != nil {
36
+			return fmt.Errorf("DROP COLUMN repo_user_name: %v", err)
37
+		} else if _, err = x.Exec("ALTER TABLE action DROP COLUMN repo_name"); err != nil {
38
+			return fmt.Errorf("DROP COLUMN repo_name: %v", err)
39
+		}
40
+	default:
41
+		log.Fatal(4, "Unrecognized DB")
42
+	}
43
+	return nil
44
+}

+ 7 - 8
models/pull.go

@@ -635,14 +635,13 @@ func NewPullRequest(repo *Repository, pull *Issue, labelIDs []int64, uuids []str
635 635
 	}
636 636
 
637 637
 	if err = NotifyWatchers(&Action{
638
-		ActUserID:    pull.Poster.ID,
639
-		ActUserName:  pull.Poster.Name,
640
-		OpType:       ActionCreatePullRequest,
641
-		Content:      fmt.Sprintf("%d|%s", pull.Index, pull.Title),
642
-		RepoID:       repo.ID,
643
-		RepoUserName: repo.Owner.Name,
644
-		RepoName:     repo.Name,
645
-		IsPrivate:    repo.IsPrivate,
638
+		ActUserID: pull.Poster.ID,
639
+		ActUser:   pull.Poster,
640
+		OpType:    ActionCreatePullRequest,
641
+		Content:   fmt.Sprintf("%d|%s", pull.Index, pull.Title),
642
+		RepoID:    repo.ID,
643
+		Repo:      repo,
644
+		IsPrivate: repo.IsPrivate,
646 645
 	}); err != nil {
647 646
 		log.Error(4, "NotifyWatchers: %v", err)
648 647
 	} else if err = pull.MailParticipants(); err != nil {

+ 33 - 8
routers/user/home.go

@@ -65,25 +65,50 @@ func retrieveFeeds(ctx *context.Context, ctxUser *models.User, userID, offset in
65 65
 
66 66
 	// Check access of private repositories.
67 67
 	feeds := make([]*models.Action, 0, len(actions))
68
-	unameAvatars := map[string]string{
69
-		ctxUser.Name: ctxUser.RelAvatarLink(),
70
-	}
68
+	userCache := map[int64]*models.User{ctxUser.ID: ctxUser}
69
+	repoCache := map[int64]*models.Repository{}
71 70
 	for _, act := range actions {
72 71
 		// Cache results to reduce queries.
73
-		_, ok := unameAvatars[act.ActUserName]
72
+		u, ok := userCache[act.ActUserID]
74 73
 		if !ok {
75
-			u, err := models.GetUserByName(act.ActUserName)
74
+			u, err = models.GetUserByID(act.ActUserID)
76 75
 			if err != nil {
77 76
 				if models.IsErrUserNotExist(err) {
78 77
 					continue
79 78
 				}
80
-				ctx.Handle(500, "GetUserByName", err)
79
+				ctx.Handle(500, "GetUserByID", err)
80
+				return
81
+			}
82
+			userCache[act.ActUserID] = u
83
+		}
84
+		act.ActUser = u
85
+
86
+		repo, ok := repoCache[act.RepoID]
87
+		if !ok {
88
+			repo, err = models.GetRepositoryByID(act.RepoID)
89
+			if err != nil {
90
+				if models.IsErrRepoNotExist(err) {
91
+					continue
92
+				}
93
+				ctx.Handle(500, "GetRepositoryByID", err)
94
+				return
95
+			}
96
+		}
97
+		act.Repo = repo
98
+
99
+		repoOwner, ok := userCache[repo.OwnerID]
100
+		if !ok {
101
+			repoOwner, err = models.GetUserByID(repo.OwnerID)
102
+			if err != nil {
103
+				if models.IsErrUserNotExist(err) {
104
+					continue
105
+				}
106
+				ctx.Handle(500, "GetUserByID", err)
81 107
 				return
82 108
 			}
83
-			unameAvatars[act.ActUserName] = u.RelAvatarLink()
84 109
 		}
110
+		repo.Owner = repoOwner
85 111
 
86
-		act.ActAvatar = unameAvatars[act.ActUserName]
87 112
 		feeds = append(feeds, act)
88 113
 	}
89 114
 	ctx.Data["Feeds"] = feeds