diff options
author | Ethan Koenig <etk39@cornell.edu> | 2017-05-25 21:38:18 -0400 |
---|---|---|
committer | Lunny Xiao <xiaolunwen@gmail.com> | 2017-05-26 09:38:18 +0800 |
commit | 0c332f0480e9aa72454641afe53aebb3b9ab6e57 (patch) | |
tree | a13b29de28b8f61b9017316d2b5433e2c5ebda96 /models | |
parent | 03912ce0142039022481ccf3798ab937e9cf4f0b (diff) | |
download | gitea-0c332f0480e9aa72454641afe53aebb3b9ab6e57.tar.gz gitea-0c332f0480e9aa72454641afe53aebb3b9ab6e57.zip |
Fix activity feed (#1779)
* Fix activity feed
Preserve actions after user/repo name change
* Add missing comment
* Fix migration, and remove fields completely
* Tests
Diffstat (limited to 'models')
-rw-r--r-- | models/action.go | 144 | ||||
-rw-r--r-- | models/action_test.go | 92 | ||||
-rw-r--r-- | models/consistency.go | 6 | ||||
-rw-r--r-- | models/fixtures/action.yml | 9 | ||||
-rw-r--r-- | models/issue.go | 15 | ||||
-rw-r--r-- | models/issue_comment.go | 13 | ||||
-rw-r--r-- | models/migrations/migrations.go | 2 | ||||
-rw-r--r-- | models/migrations/v34.go | 44 | ||||
-rw-r--r-- | models/pull.go | 15 |
9 files changed, 193 insertions, 147 deletions
diff --git a/models/action.go b/models/action.go index 6f76cbc4e3..4af81ce80a 100644 --- a/models/action.go +++ b/models/action.go @@ -70,20 +70,18 @@ func init() { // repository. It implemented interface base.Actioner so that can be // used in template render. type Action struct { - ID int64 `xorm:"pk autoincr"` - UserID int64 `xorm:"INDEX"` // Receiver user id. - OpType ActionType - ActUserID int64 `xorm:"INDEX"` // Action user id. - ActUserName string // Action user name. - ActAvatar string `xorm:"-"` - RepoID int64 `xorm:"INDEX"` - RepoUserName string - RepoName string - RefName string - IsPrivate bool `xorm:"INDEX NOT NULL DEFAULT false"` - Content string `xorm:"TEXT"` - Created time.Time `xorm:"-"` - CreatedUnix int64 `xorm:"INDEX"` + ID int64 `xorm:"pk autoincr"` + UserID int64 `xorm:"INDEX"` // Receiver user id. + OpType ActionType + ActUserID int64 `xorm:"INDEX"` // Action user id. + ActUser *User `xorm:"-"` + RepoID int64 `xorm:"INDEX"` + Repo *Repository `xorm:"-"` + RefName string + IsPrivate bool `xorm:"INDEX NOT NULL DEFAULT false"` + Content string `xorm:"TEXT"` + Created time.Time `xorm:"-"` + CreatedUnix int64 `xorm:"INDEX"` } // BeforeInsert will be invoked by XORM before inserting a record @@ -106,42 +104,71 @@ func (a *Action) GetOpType() int { return int(a.OpType) } +func (a *Action) loadActUser() { + if a.ActUser != nil { + return + } + var err error + a.ActUser, err = GetUserByID(a.ActUserID) + if err == nil { + return + } else if IsErrUserNotExist(err) { + a.ActUser = NewGhostUser() + } else { + log.Error(4, "GetUserByID(%d): %v", a.ActUserID, err) + } +} + +func (a *Action) loadRepo() { + if a.ActUser != nil { + return + } + var err error + a.Repo, err = GetRepositoryByID(a.RepoID) + if err != nil { + log.Error(4, "GetRepositoryByID(%d): %v", a.RepoID, err) + } +} + // GetActUserName gets the action's user name. func (a *Action) GetActUserName() string { - return a.ActUserName + a.loadActUser() + return a.ActUser.Name } // ShortActUserName gets the action's user name trimmed to max 20 // chars. func (a *Action) ShortActUserName() string { - return base.EllipsisString(a.ActUserName, 20) + return base.EllipsisString(a.GetActUserName(), 20) } // GetRepoUserName returns the name of the action repository owner. func (a *Action) GetRepoUserName() string { - return a.RepoUserName + a.loadRepo() + return a.Repo.MustOwner().Name } // ShortRepoUserName returns the name of the action repository owner // trimmed to max 20 chars. func (a *Action) ShortRepoUserName() string { - return base.EllipsisString(a.RepoUserName, 20) + return base.EllipsisString(a.GetRepoUserName(), 20) } // GetRepoName returns the name of the action repository. func (a *Action) GetRepoName() string { - return a.RepoName + a.loadRepo() + return a.Repo.Name } // ShortRepoName returns the name of the action repository // trimmed to max 33 chars. func (a *Action) ShortRepoName() string { - return base.EllipsisString(a.RepoName, 33) + return base.EllipsisString(a.GetRepoName(), 33) } // GetRepoPath returns the virtual path to the action repository. func (a *Action) GetRepoPath() string { - return path.Join(a.RepoUserName, a.RepoName) + return path.Join(a.GetRepoUserName(), a.GetRepoName()) } // ShortRepoPath returns the virtual path to the action repository @@ -205,13 +232,12 @@ func (a *Action) GetIssueContent() string { func newRepoAction(e Engine, u *User, repo *Repository) (err error) { if err = notifyWatchers(e, &Action{ - ActUserID: u.ID, - ActUserName: u.Name, - OpType: ActionCreateRepo, - RepoID: repo.ID, - RepoUserName: repo.Owner.Name, - RepoName: repo.Name, - IsPrivate: repo.IsPrivate, + ActUserID: u.ID, + ActUser: u, + OpType: ActionCreateRepo, + RepoID: repo.ID, + Repo: repo, + IsPrivate: repo.IsPrivate, }); err != nil { return fmt.Errorf("notify watchers '%d/%d': %v", u.ID, repo.ID, err) } @@ -227,14 +253,13 @@ func NewRepoAction(u *User, repo *Repository) (err error) { func renameRepoAction(e Engine, actUser *User, oldRepoName string, repo *Repository) (err error) { if err = notifyWatchers(e, &Action{ - ActUserID: actUser.ID, - ActUserName: actUser.Name, - OpType: ActionRenameRepo, - RepoID: repo.ID, - RepoUserName: repo.Owner.Name, - RepoName: repo.Name, - IsPrivate: repo.IsPrivate, - Content: oldRepoName, + ActUserID: actUser.ID, + ActUser: actUser, + OpType: ActionRenameRepo, + RepoID: repo.ID, + Repo: repo, + IsPrivate: repo.IsPrivate, + Content: oldRepoName, }); err != nil { return fmt.Errorf("notify watchers: %v", err) } @@ -521,15 +546,14 @@ func CommitRepoAction(opts CommitRepoActionOptions) error { refName := git.RefEndName(opts.RefFullName) if err = NotifyWatchers(&Action{ - ActUserID: pusher.ID, - ActUserName: pusher.Name, - OpType: opType, - Content: string(data), - RepoID: repo.ID, - RepoUserName: repo.MustOwner().Name, - RepoName: repo.Name, - RefName: refName, - IsPrivate: repo.IsPrivate, + ActUserID: pusher.ID, + ActUser: pusher, + OpType: opType, + Content: string(data), + RepoID: repo.ID, + Repo: repo, + RefName: refName, + IsPrivate: repo.IsPrivate, }); err != nil { return fmt.Errorf("NotifyWatchers: %v", err) } @@ -598,14 +622,13 @@ func CommitRepoAction(opts CommitRepoActionOptions) error { func transferRepoAction(e Engine, doer, oldOwner *User, repo *Repository) (err error) { if err = notifyWatchers(e, &Action{ - ActUserID: doer.ID, - ActUserName: doer.Name, - OpType: ActionTransferRepo, - RepoID: repo.ID, - RepoUserName: repo.Owner.Name, - RepoName: repo.Name, - IsPrivate: repo.IsPrivate, - Content: path.Join(oldOwner.Name, repo.Name), + ActUserID: doer.ID, + ActUser: doer, + OpType: ActionTransferRepo, + RepoID: repo.ID, + Repo: repo, + IsPrivate: repo.IsPrivate, + Content: path.Join(oldOwner.Name, repo.Name), }); err != nil { return fmt.Errorf("notifyWatchers: %v", err) } @@ -628,14 +651,13 @@ func TransferRepoAction(doer, oldOwner *User, repo *Repository) error { func mergePullRequestAction(e Engine, doer *User, repo *Repository, issue *Issue) error { return notifyWatchers(e, &Action{ - ActUserID: doer.ID, - ActUserName: doer.Name, - OpType: ActionMergePullRequest, - Content: fmt.Sprintf("%d|%s", issue.Index, issue.Title), - RepoID: repo.ID, - RepoUserName: repo.Owner.Name, - RepoName: repo.Name, - IsPrivate: repo.IsPrivate, + ActUserID: doer.ID, + ActUser: doer, + OpType: ActionMergePullRequest, + Content: fmt.Sprintf("%d|%s", issue.Index, issue.Title), + RepoID: repo.ID, + Repo: repo, + IsPrivate: repo.IsPrivate, }) } diff --git a/models/action_test.go b/models/action_test.go index cb36966ec7..c6d3911a63 100644 --- a/models/action_test.go +++ b/models/action_test.go @@ -1,6 +1,7 @@ package models import ( + "path" "strings" "testing" @@ -10,22 +11,21 @@ import ( ) func TestAction_GetRepoPath(t *testing.T) { - action := &Action{ - RepoUserName: "username", - RepoName: "reponame", - } - assert.Equal(t, "username/reponame", action.GetRepoPath()) + assert.NoError(t, PrepareTestDatabase()) + repo := AssertExistsAndLoadBean(t, &Repository{}).(*Repository) + owner := AssertExistsAndLoadBean(t, &User{ID: repo.OwnerID}).(*User) + action := &Action{RepoID: repo.ID} + assert.Equal(t, path.Join(owner.Name, repo.Name), action.GetRepoPath()) } func TestAction_GetRepoLink(t *testing.T) { - action := &Action{ - RepoUserName: "username", - RepoName: "reponame", - } + assert.NoError(t, PrepareTestDatabase()) + repo := AssertExistsAndLoadBean(t, &Repository{}).(*Repository) + owner := AssertExistsAndLoadBean(t, &User{ID: repo.OwnerID}).(*User) + action := &Action{RepoID: repo.ID} setting.AppSubURL = "/suburl/" - assert.Equal(t, "/suburl/username/reponame", action.GetRepoLink()) - setting.AppSubURL = "" - assert.Equal(t, "/username/reponame", action.GetRepoLink()) + expected := path.Join(setting.AppSubURL, owner.Name, repo.Name) + assert.Equal(t, expected, action.GetRepoLink()) } func TestNewRepoAction(t *testing.T) { @@ -36,13 +36,12 @@ func TestNewRepoAction(t *testing.T) { repo.Owner = user actionBean := &Action{ - OpType: ActionCreateRepo, - ActUserID: user.ID, - RepoID: repo.ID, - ActUserName: user.Name, - RepoName: repo.Name, - RepoUserName: repo.Owner.Name, - IsPrivate: repo.IsPrivate, + OpType: ActionCreateRepo, + ActUserID: user.ID, + RepoID: repo.ID, + ActUser: user, + Repo: repo, + IsPrivate: repo.IsPrivate, } AssertNotExistsBean(t, actionBean) @@ -64,14 +63,13 @@ func TestRenameRepoAction(t *testing.T) { repo.LowerName = strings.ToLower(newRepoName) actionBean := &Action{ - OpType: ActionRenameRepo, - ActUserID: user.ID, - ActUserName: user.Name, - RepoID: repo.ID, - RepoName: repo.Name, - RepoUserName: repo.Owner.Name, - IsPrivate: repo.IsPrivate, - Content: oldRepoName, + OpType: ActionRenameRepo, + ActUserID: user.ID, + ActUser: user, + RepoID: repo.ID, + Repo: repo, + IsPrivate: repo.IsPrivate, + Content: oldRepoName, } AssertNotExistsBean(t, actionBean) assert.NoError(t, RenameRepoAction(user, oldRepoName, repo)) @@ -232,13 +230,13 @@ func TestCommitRepoAction(t *testing.T) { pushCommits.Len = len(pushCommits.Commits) actionBean := &Action{ - OpType: ActionCommitRepo, - ActUserID: user.ID, - ActUserName: user.Name, - RepoID: repo.ID, - RepoName: repo.Name, - RefName: "refName", - IsPrivate: repo.IsPrivate, + OpType: ActionCommitRepo, + ActUserID: user.ID, + ActUser: user, + RepoID: repo.ID, + Repo: repo, + RefName: "refName", + IsPrivate: repo.IsPrivate, } AssertNotExistsBean(t, actionBean) assert.NoError(t, CommitRepoAction(CommitRepoActionOptions{ @@ -265,13 +263,12 @@ func TestTransferRepoAction(t *testing.T) { repo.Owner = user4 actionBean := &Action{ - OpType: ActionTransferRepo, - ActUserID: user2.ID, - ActUserName: user2.Name, - RepoID: repo.ID, - RepoName: repo.Name, - RepoUserName: repo.Owner.Name, - IsPrivate: repo.IsPrivate, + OpType: ActionTransferRepo, + ActUserID: user2.ID, + ActUser: user2, + RepoID: repo.ID, + Repo: repo, + IsPrivate: repo.IsPrivate, } AssertNotExistsBean(t, actionBean) assert.NoError(t, TransferRepoAction(user2, user2, repo)) @@ -290,13 +287,12 @@ func TestMergePullRequestAction(t *testing.T) { issue := AssertExistsAndLoadBean(t, &Issue{ID: 3, RepoID: repo.ID}).(*Issue) actionBean := &Action{ - OpType: ActionMergePullRequest, - ActUserID: user.ID, - ActUserName: user.Name, - RepoID: repo.ID, - RepoName: repo.Name, - RepoUserName: repo.Owner.Name, - IsPrivate: repo.IsPrivate, + OpType: ActionMergePullRequest, + ActUserID: user.ID, + ActUser: user, + RepoID: repo.ID, + Repo: repo, + IsPrivate: repo.IsPrivate, } AssertNotExistsBean(t, actionBean) assert.NoError(t, MergePullRequestAction(user, repo, issue)) diff --git a/models/consistency.go b/models/consistency.go index 77308e538e..0c279eaaf8 100644 --- a/models/consistency.go +++ b/models/consistency.go @@ -162,11 +162,5 @@ func (team *Team) checkForConsistency(t *testing.T) { func (action *Action) checkForConsistency(t *testing.T) { repo := AssertExistsAndLoadBean(t, &Repository{ID: action.RepoID}).(*Repository) - owner := AssertExistsAndLoadBean(t, &User{ID: repo.OwnerID}).(*User) - actor := AssertExistsAndLoadBean(t, &User{ID: action.ActUserID}).(*User) - - assert.Equal(t, repo.Name, action.RepoName, "action: %+v", action) assert.Equal(t, repo.IsPrivate, action.IsPrivate, "action: %+v", action) - assert.Equal(t, owner.Name, action.RepoUserName, "action: %+v", action) - assert.Equal(t, actor.Name, action.ActUserName, "action: %+v", action) } diff --git a/models/fixtures/action.yml b/models/fixtures/action.yml index 94d8e5759c..10c0dc1298 100644 --- a/models/fixtures/action.yml +++ b/models/fixtures/action.yml @@ -3,10 +3,7 @@ user_id: 2 op_type: 12 # close issue act_user_id: 2 - act_user_name: user2 repo_id: 2 - repo_user_name: user2 - repo_name: repo2 is_private: true - @@ -14,10 +11,7 @@ user_id: 3 op_type: 2 # rename repo act_user_id: 3 - act_user_name: user3 repo_id: 3 - repo_user_name: user3 - repo_name: repo3 is_private: true content: oldRepoName @@ -26,8 +20,5 @@ user_id: 11 op_type: 1 # create repo act_user_id: 11 - act_user_name: user11 repo_id: 9 - repo_user_name: user11 - repo_name: repo9 is_private: false diff --git a/models/issue.go b/models/issue.go index 8de6ea9cb9..b78c6ba3f1 100644 --- a/models/issue.go +++ b/models/issue.go @@ -918,14 +918,13 @@ func NewIssue(repo *Repository, issue *Issue, labelIDs []int64, uuids []string) } if err = NotifyWatchers(&Action{ - ActUserID: issue.Poster.ID, - ActUserName: issue.Poster.Name, - OpType: ActionCreateIssue, - Content: fmt.Sprintf("%d|%s", issue.Index, issue.Title), - RepoID: repo.ID, - RepoUserName: repo.Owner.Name, - RepoName: repo.Name, - IsPrivate: repo.IsPrivate, + ActUserID: issue.Poster.ID, + ActUser: issue.Poster, + OpType: ActionCreateIssue, + Content: fmt.Sprintf("%d|%s", issue.Index, issue.Title), + RepoID: repo.ID, + Repo: repo, + IsPrivate: repo.IsPrivate, }); err != nil { log.Error(4, "NotifyWatchers: %v", err) } diff --git a/models/issue_comment.go b/models/issue_comment.go index a65abfe012..69edf28f54 100644 --- a/models/issue_comment.go +++ b/models/issue_comment.go @@ -329,13 +329,12 @@ func createComment(e *xorm.Session, opts *CreateCommentOptions) (_ *Comment, err // Compose comment action, could be plain comment, close or reopen issue/pull request. // This object will be used to notify watchers in the end of function. act := &Action{ - ActUserID: opts.Doer.ID, - ActUserName: opts.Doer.Name, - Content: fmt.Sprintf("%d|%s", opts.Issue.Index, strings.Split(opts.Content, "\n")[0]), - RepoID: opts.Repo.ID, - RepoUserName: opts.Repo.Owner.Name, - RepoName: opts.Repo.Name, - IsPrivate: opts.Repo.IsPrivate, + ActUserID: opts.Doer.ID, + ActUser: opts.Doer, + Content: fmt.Sprintf("%d|%s", opts.Issue.Index, strings.Split(opts.Content, "\n")[0]), + RepoID: opts.Repo.ID, + Repo: opts.Repo, + IsPrivate: opts.Repo.IsPrivate, } // Check comment type. diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go index 2973064152..5822533ee2 100644 --- a/models/migrations/migrations.go +++ b/models/migrations/migrations.go @@ -114,6 +114,8 @@ var migrations = []Migration{ NewMigration("add field for login source synchronization", addLoginSourceSyncEnabledColumn), // v32 -> v33 NewMigration("add units for team", addUnitsToRepoTeam), + // v33 -> v34 + NewMigration("remove columns from action", removeActionColumns), } // Migrate database to current version diff --git a/models/migrations/v34.go b/models/migrations/v34.go new file mode 100644 index 0000000000..94fcd870f0 --- /dev/null +++ b/models/migrations/v34.go @@ -0,0 +1,44 @@ +// Copyright 2017 Gitea. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package migrations + +import ( + "fmt" + + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/setting" + + "github.com/go-xorm/xorm" +) + +// ActionV34 describes the removed fields +type ActionV34 struct { + ActUserName string `xorm:"-"` + RepoUserName string `xorm:"-"` + RepoName string `xorm:"-"` +} + +// TableName will be invoked by XORM to customize the table name +func (*ActionV34) TableName() string { + return "action" +} + +func removeActionColumns(x *xorm.Engine) error { + switch { + case setting.UseSQLite3: + log.Warn("Unable to drop columns in SQLite") + case setting.UseMySQL, setting.UsePostgreSQL, setting.UseMSSQL, setting.UseTiDB: + if _, err := x.Exec("ALTER TABLE action DROP COLUMN act_user_name"); err != nil { + return fmt.Errorf("DROP COLUMN act_user_name: %v", err) + } else if _, err = x.Exec("ALTER TABLE action DROP COLUMN repo_user_name"); err != nil { + return fmt.Errorf("DROP COLUMN repo_user_name: %v", err) + } else if _, err = x.Exec("ALTER TABLE action DROP COLUMN repo_name"); err != nil { + return fmt.Errorf("DROP COLUMN repo_name: %v", err) + } + default: + log.Fatal(4, "Unrecognized DB") + } + return nil +} diff --git a/models/pull.go b/models/pull.go index 64fa51b61b..76a646200e 100644 --- a/models/pull.go +++ b/models/pull.go @@ -635,14 +635,13 @@ func NewPullRequest(repo *Repository, pull *Issue, labelIDs []int64, uuids []str } if err = NotifyWatchers(&Action{ - ActUserID: pull.Poster.ID, - ActUserName: pull.Poster.Name, - OpType: ActionCreatePullRequest, - Content: fmt.Sprintf("%d|%s", pull.Index, pull.Title), - RepoID: repo.ID, - RepoUserName: repo.Owner.Name, - RepoName: repo.Name, - IsPrivate: repo.IsPrivate, + ActUserID: pull.Poster.ID, + ActUser: pull.Poster, + OpType: ActionCreatePullRequest, + Content: fmt.Sprintf("%d|%s", pull.Index, pull.Title), + RepoID: repo.ID, + Repo: repo, + IsPrivate: repo.IsPrivate, }); err != nil { log.Error(4, "NotifyWatchers: %v", err) } else if err = pull.MailParticipants(); err != nil { |