Migrate reactions when migrating repository from github (#9599)
* Migrate reactions when migrating repository from github * fix missed sleep * fix tests * update reactions when external user binding * Fix test * fix tests * change the copy head * fix test * fix migrator add/delete reaction
This commit is contained in:
parent
4e566df1c6
commit
2b3e931cde
18 changed files with 329 additions and 101 deletions
|
@ -177,5 +177,9 @@ func UpdateMigrationsByType(tp structs.GitServiceType, externalUserID string, us
|
|||
return err
|
||||
}
|
||||
|
||||
return UpdateReleasesMigrationsByType(tp, externalUserID, userID)
|
||||
if err := UpdateReleasesMigrationsByType(tp, externalUserID, userID); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return UpdateReactionsMigrationsByType(tp, externalUserID, userID)
|
||||
}
|
||||
|
|
|
@ -218,8 +218,11 @@ func (issue *Issue) loadReactions(e Engine) (err error) {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err = issue.loadRepo(e); err != nil {
|
||||
return err
|
||||
}
|
||||
// Load reaction user data
|
||||
if _, err := ReactionList(reactions).loadUsers(e); err != nil {
|
||||
if _, err := ReactionList(reactions).loadUsers(e, issue.Repo); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -1836,3 +1839,17 @@ func UpdateIssuesMigrationsByType(gitServiceType structs.GitServiceType, origina
|
|||
})
|
||||
return err
|
||||
}
|
||||
|
||||
// UpdateReactionsMigrationsByType updates all migrated repositories' reactions from gitServiceType to replace originalAuthorID to posterID
|
||||
func UpdateReactionsMigrationsByType(gitServiceType structs.GitServiceType, originalAuthorID string, userID int64) error {
|
||||
_, err := x.Table("reaction").
|
||||
Join("INNER", "issue", "issue.id = reaction.issue_id").
|
||||
Where("issue.repo_id IN (SELECT id FROM repository WHERE original_service_type = ?)", gitServiceType).
|
||||
And("reaction.original_author_id = ?", originalAuthorID).
|
||||
Update(map[string]interface{}{
|
||||
"user_id": userID,
|
||||
"original_author": "",
|
||||
"original_author_id": 0,
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -425,7 +425,7 @@ func (c *Comment) LoadDepIssueDetails() (err error) {
|
|||
return err
|
||||
}
|
||||
|
||||
func (c *Comment) loadReactions(e Engine) (err error) {
|
||||
func (c *Comment) loadReactions(e Engine, repo *Repository) (err error) {
|
||||
if c.Reactions != nil {
|
||||
return nil
|
||||
}
|
||||
|
@ -437,15 +437,15 @@ func (c *Comment) loadReactions(e Engine) (err error) {
|
|||
return err
|
||||
}
|
||||
// Load reaction user data
|
||||
if _, err := c.Reactions.LoadUsers(); err != nil {
|
||||
if _, err := c.Reactions.loadUsers(e, repo); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// LoadReactions loads comment reactions
|
||||
func (c *Comment) LoadReactions() error {
|
||||
return c.loadReactions(x)
|
||||
func (c *Comment) LoadReactions(repo *Repository) error {
|
||||
return c.loadReactions(x, repo)
|
||||
}
|
||||
|
||||
func (c *Comment) loadReview(e Engine) (err error) {
|
||||
|
|
|
@ -17,13 +17,15 @@ import (
|
|||
|
||||
// Reaction represents a reactions on issues and comments.
|
||||
type Reaction struct {
|
||||
ID int64 `xorm:"pk autoincr"`
|
||||
Type string `xorm:"INDEX UNIQUE(s) NOT NULL"`
|
||||
IssueID int64 `xorm:"INDEX UNIQUE(s) NOT NULL"`
|
||||
CommentID int64 `xorm:"INDEX UNIQUE(s)"`
|
||||
UserID int64 `xorm:"INDEX UNIQUE(s) NOT NULL"`
|
||||
User *User `xorm:"-"`
|
||||
CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"`
|
||||
ID int64 `xorm:"pk autoincr"`
|
||||
Type string `xorm:"INDEX UNIQUE(s) NOT NULL"`
|
||||
IssueID int64 `xorm:"INDEX UNIQUE(s) NOT NULL"`
|
||||
CommentID int64 `xorm:"INDEX UNIQUE(s)"`
|
||||
UserID int64 `xorm:"INDEX UNIQUE(s) NOT NULL"`
|
||||
OriginalAuthorID int64 `xorm:"INDEX UNIQUE(s) NOT NULL DEFAULT(0)"`
|
||||
OriginalAuthor string
|
||||
User *User `xorm:"-"`
|
||||
CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"`
|
||||
}
|
||||
|
||||
// FindReactionsOptions describes the conditions to Find reactions
|
||||
|
@ -49,7 +51,10 @@ func (opts *FindReactionsOptions) toConds() builder.Cond {
|
|||
cond = cond.And(builder.Eq{"reaction.comment_id": 0})
|
||||
}
|
||||
if opts.UserID > 0 {
|
||||
cond = cond.And(builder.Eq{"reaction.user_id": opts.UserID})
|
||||
cond = cond.And(builder.Eq{
|
||||
"reaction.user_id": opts.UserID,
|
||||
"reaction.original_author_id": 0,
|
||||
})
|
||||
}
|
||||
if opts.Reaction != "" {
|
||||
cond = cond.And(builder.Eq{"reaction.type": opts.Reaction})
|
||||
|
@ -173,7 +178,7 @@ func deleteReaction(e *xorm.Session, opts *ReactionOptions) error {
|
|||
if opts.Comment != nil {
|
||||
reaction.CommentID = opts.Comment.ID
|
||||
}
|
||||
_, err := e.Delete(reaction)
|
||||
_, err := e.Where("original_author_id = 0").Delete(reaction)
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -233,7 +238,7 @@ func (list ReactionList) HasUser(userID int64) bool {
|
|||
return false
|
||||
}
|
||||
for _, reaction := range list {
|
||||
if reaction.UserID == userID {
|
||||
if reaction.OriginalAuthor == "" && reaction.UserID == userID {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
@ -252,6 +257,9 @@ func (list ReactionList) GroupByType() map[string]ReactionList {
|
|||
func (list ReactionList) getUserIDs() []int64 {
|
||||
userIDs := make(map[int64]struct{}, len(list))
|
||||
for _, reaction := range list {
|
||||
if reaction.OriginalAuthor != "" {
|
||||
continue
|
||||
}
|
||||
if _, ok := userIDs[reaction.UserID]; !ok {
|
||||
userIDs[reaction.UserID] = struct{}{}
|
||||
}
|
||||
|
@ -259,7 +267,7 @@ func (list ReactionList) getUserIDs() []int64 {
|
|||
return keysInt64(userIDs)
|
||||
}
|
||||
|
||||
func (list ReactionList) loadUsers(e Engine) ([]*User, error) {
|
||||
func (list ReactionList) loadUsers(e Engine, repo *Repository) ([]*User, error) {
|
||||
if len(list) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
@ -274,7 +282,9 @@ func (list ReactionList) loadUsers(e Engine) ([]*User, error) {
|
|||
}
|
||||
|
||||
for _, reaction := range list {
|
||||
if user, ok := userMaps[reaction.UserID]; ok {
|
||||
if reaction.OriginalAuthor != "" {
|
||||
reaction.User = NewReplaceUser(fmt.Sprintf("%s(%s)", reaction.OriginalAuthor, repo.OriginalServiceType.Name()))
|
||||
} else if user, ok := userMaps[reaction.UserID]; ok {
|
||||
reaction.User = user
|
||||
} else {
|
||||
reaction.User = NewGhostUser()
|
||||
|
@ -284,8 +294,8 @@ func (list ReactionList) loadUsers(e Engine) ([]*User, error) {
|
|||
}
|
||||
|
||||
// LoadUsers loads reactions' all users
|
||||
func (list ReactionList) LoadUsers() ([]*User, error) {
|
||||
return list.loadUsers(x)
|
||||
func (list ReactionList) LoadUsers(repo *Repository) ([]*User, error) {
|
||||
return list.loadUsers(x, repo)
|
||||
}
|
||||
|
||||
// GetFirstUsers returns first reacted user display names separated by comma
|
||||
|
|
|
@ -132,6 +132,7 @@ func TestIssueCommentDeleteReaction(t *testing.T) {
|
|||
user4 := AssertExistsAndLoadBean(t, &User{ID: 4}).(*User)
|
||||
|
||||
issue1 := AssertExistsAndLoadBean(t, &Issue{ID: 1}).(*Issue)
|
||||
repo1 := AssertExistsAndLoadBean(t, &Repository{ID: issue1.RepoID}).(*Repository)
|
||||
|
||||
comment1 := AssertExistsAndLoadBean(t, &Comment{ID: 1}).(*Comment)
|
||||
|
||||
|
@ -140,7 +141,7 @@ func TestIssueCommentDeleteReaction(t *testing.T) {
|
|||
addReaction(t, user3, issue1, comment1, "heart")
|
||||
addReaction(t, user4, issue1, comment1, "+1")
|
||||
|
||||
err := comment1.LoadReactions()
|
||||
err := comment1.LoadReactions(repo1)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, comment1.Reactions, 4)
|
||||
|
||||
|
|
|
@ -63,6 +63,13 @@ func insertIssue(sess *xorm.Session, issue *Issue) error {
|
|||
return err
|
||||
}
|
||||
|
||||
for _, reaction := range issue.Reactions {
|
||||
reaction.IssueID = issue.ID
|
||||
}
|
||||
if _, err := sess.Insert(issue.Reactions); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cols := make([]string, 0)
|
||||
if !issue.IsPull {
|
||||
sess.ID(issue.RepoID).Incr("num_issues")
|
||||
|
@ -130,9 +137,20 @@ func InsertIssueComments(comments []*Comment) error {
|
|||
if err := sess.Begin(); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := sess.NoAutoTime().Insert(comments); err != nil {
|
||||
return err
|
||||
for _, comment := range comments {
|
||||
if _, err := sess.NoAutoTime().Insert(comment); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, reaction := range comment.Reactions {
|
||||
reaction.IssueID = comment.IssueID
|
||||
reaction.CommentID = comment.ID
|
||||
}
|
||||
if _, err := sess.Insert(comment.Reactions); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
for issueID := range issueIDs {
|
||||
if _, err := sess.Exec("UPDATE issue set num_comments = (SELECT count(*) FROM comment WHERE issue_id = ?) WHERE id = ?", issueID, issueID); err != nil {
|
||||
return err
|
||||
|
|
|
@ -300,6 +300,8 @@ var migrations = []Migration{
|
|||
NewMigration("add is_restricted column for users table", addIsRestricted),
|
||||
// v122 -> v123
|
||||
NewMigration("Add Require Signed Commits to ProtectedBranch", addRequireSignedCommits),
|
||||
// v123 -> v124
|
||||
NewMigration("Add original informations for reactions", addReactionOriginals),
|
||||
}
|
||||
|
||||
// Migrate database to current version
|
||||
|
|
18
models/migrations/v123.go
Normal file
18
models/migrations/v123.go
Normal file
|
@ -0,0 +1,18 @@
|
|||
// Copyright 2020 The Gitea Authors. 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 (
|
||||
"xorm.io/xorm"
|
||||
)
|
||||
|
||||
func addReactionOriginals(x *xorm.Engine) error {
|
||||
type Reaction struct {
|
||||
OriginalAuthorID int64 `xorm:"INDEX NOT NULL DEFAULT(0)"`
|
||||
OriginalAuthor string
|
||||
}
|
||||
|
||||
return x.Sync2(new(Reaction))
|
||||
}
|
|
@ -793,6 +793,15 @@ func NewGhostUser() *User {
|
|||
}
|
||||
}
|
||||
|
||||
// NewReplaceUser creates and returns a fake user for external user
|
||||
func NewReplaceUser(name string) *User {
|
||||
return &User{
|
||||
ID: -1,
|
||||
Name: name,
|
||||
LowerName: strings.ToLower(name),
|
||||
}
|
||||
}
|
||||
|
||||
// IsGhost check if user is fake user for a deleted account
|
||||
func (u *User) IsGhost() bool {
|
||||
if u == nil {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue