* 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 reactiontags/v1.21.12.1
| @@ -177,5 +177,9 @@ func UpdateMigrationsByType(tp structs.GitServiceType, externalUserID string, us | |||||
| return err | 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 { | if err != nil { | ||||
| return err | return err | ||||
| } | } | ||||
| if err = issue.loadRepo(e); err != nil { | |||||
| return err | |||||
| } | |||||
| // Load reaction user data | // Load reaction user data | ||||
| if _, err := ReactionList(reactions).loadUsers(e); err != nil { | |||||
| if _, err := ReactionList(reactions).loadUsers(e, issue.Repo); err != nil { | |||||
| return err | return err | ||||
| } | } | ||||
| @@ -1836,3 +1839,17 @@ func UpdateIssuesMigrationsByType(gitServiceType structs.GitServiceType, origina | |||||
| }) | }) | ||||
| return err | 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 | return err | ||||
| } | } | ||||
| func (c *Comment) loadReactions(e Engine) (err error) { | |||||
| func (c *Comment) loadReactions(e Engine, repo *Repository) (err error) { | |||||
| if c.Reactions != nil { | if c.Reactions != nil { | ||||
| return nil | return nil | ||||
| } | } | ||||
| @@ -437,15 +437,15 @@ func (c *Comment) loadReactions(e Engine) (err error) { | |||||
| return err | return err | ||||
| } | } | ||||
| // Load reaction user data | // Load reaction user data | ||||
| if _, err := c.Reactions.LoadUsers(); err != nil { | |||||
| if _, err := c.Reactions.loadUsers(e, repo); err != nil { | |||||
| return err | return err | ||||
| } | } | ||||
| return nil | return nil | ||||
| } | } | ||||
| // LoadReactions loads comment reactions | // 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) { | func (c *Comment) loadReview(e Engine) (err error) { | ||||
| @@ -17,13 +17,15 @@ import ( | |||||
| // Reaction represents a reactions on issues and comments. | // Reaction represents a reactions on issues and comments. | ||||
| type Reaction struct { | 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 | // 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}) | cond = cond.And(builder.Eq{"reaction.comment_id": 0}) | ||||
| } | } | ||||
| if opts.UserID > 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 != "" { | if opts.Reaction != "" { | ||||
| cond = cond.And(builder.Eq{"reaction.type": 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 { | if opts.Comment != nil { | ||||
| reaction.CommentID = opts.Comment.ID | reaction.CommentID = opts.Comment.ID | ||||
| } | } | ||||
| _, err := e.Delete(reaction) | |||||
| _, err := e.Where("original_author_id = 0").Delete(reaction) | |||||
| return err | return err | ||||
| } | } | ||||
| @@ -233,7 +238,7 @@ func (list ReactionList) HasUser(userID int64) bool { | |||||
| return false | return false | ||||
| } | } | ||||
| for _, reaction := range list { | for _, reaction := range list { | ||||
| if reaction.UserID == userID { | |||||
| if reaction.OriginalAuthor == "" && reaction.UserID == userID { | |||||
| return true | return true | ||||
| } | } | ||||
| } | } | ||||
| @@ -252,6 +257,9 @@ func (list ReactionList) GroupByType() map[string]ReactionList { | |||||
| func (list ReactionList) getUserIDs() []int64 { | func (list ReactionList) getUserIDs() []int64 { | ||||
| userIDs := make(map[int64]struct{}, len(list)) | userIDs := make(map[int64]struct{}, len(list)) | ||||
| for _, reaction := range list { | for _, reaction := range list { | ||||
| if reaction.OriginalAuthor != "" { | |||||
| continue | |||||
| } | |||||
| if _, ok := userIDs[reaction.UserID]; !ok { | if _, ok := userIDs[reaction.UserID]; !ok { | ||||
| userIDs[reaction.UserID] = struct{}{} | userIDs[reaction.UserID] = struct{}{} | ||||
| } | } | ||||
| @@ -259,7 +267,7 @@ func (list ReactionList) getUserIDs() []int64 { | |||||
| return keysInt64(userIDs) | 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 { | if len(list) == 0 { | ||||
| return nil, nil | return nil, nil | ||||
| } | } | ||||
| @@ -274,7 +282,9 @@ func (list ReactionList) loadUsers(e Engine) ([]*User, error) { | |||||
| } | } | ||||
| for _, reaction := range list { | 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 | reaction.User = user | ||||
| } else { | } else { | ||||
| reaction.User = NewGhostUser() | reaction.User = NewGhostUser() | ||||
| @@ -284,8 +294,8 @@ func (list ReactionList) loadUsers(e Engine) ([]*User, error) { | |||||
| } | } | ||||
| // LoadUsers loads reactions' all users | // 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 | // 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) | user4 := AssertExistsAndLoadBean(t, &User{ID: 4}).(*User) | ||||
| issue1 := AssertExistsAndLoadBean(t, &Issue{ID: 1}).(*Issue) | issue1 := AssertExistsAndLoadBean(t, &Issue{ID: 1}).(*Issue) | ||||
| repo1 := AssertExistsAndLoadBean(t, &Repository{ID: issue1.RepoID}).(*Repository) | |||||
| comment1 := AssertExistsAndLoadBean(t, &Comment{ID: 1}).(*Comment) | comment1 := AssertExistsAndLoadBean(t, &Comment{ID: 1}).(*Comment) | ||||
| @@ -140,7 +141,7 @@ func TestIssueCommentDeleteReaction(t *testing.T) { | |||||
| addReaction(t, user3, issue1, comment1, "heart") | addReaction(t, user3, issue1, comment1, "heart") | ||||
| addReaction(t, user4, issue1, comment1, "+1") | addReaction(t, user4, issue1, comment1, "+1") | ||||
| err := comment1.LoadReactions() | |||||
| err := comment1.LoadReactions(repo1) | |||||
| assert.NoError(t, err) | assert.NoError(t, err) | ||||
| assert.Len(t, comment1.Reactions, 4) | assert.Len(t, comment1.Reactions, 4) | ||||
| @@ -63,6 +63,13 @@ func insertIssue(sess *xorm.Session, issue *Issue) error { | |||||
| return err | 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) | cols := make([]string, 0) | ||||
| if !issue.IsPull { | if !issue.IsPull { | ||||
| sess.ID(issue.RepoID).Incr("num_issues") | sess.ID(issue.RepoID).Incr("num_issues") | ||||
| @@ -130,9 +137,20 @@ func InsertIssueComments(comments []*Comment) error { | |||||
| if err := sess.Begin(); err != nil { | if err := sess.Begin(); err != nil { | ||||
| return err | 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 { | 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 { | if _, err := sess.Exec("UPDATE issue set num_comments = (SELECT count(*) FROM comment WHERE issue_id = ?) WHERE id = ?", issueID, issueID); err != nil { | ||||
| return err | return err | ||||
| @@ -300,6 +300,8 @@ var migrations = []Migration{ | |||||
| NewMigration("add is_restricted column for users table", addIsRestricted), | NewMigration("add is_restricted column for users table", addIsRestricted), | ||||
| // v122 -> v123 | // v122 -> v123 | ||||
| NewMigration("Add Require Signed Commits to ProtectedBranch", addRequireSignedCommits), | NewMigration("Add Require Signed Commits to ProtectedBranch", addRequireSignedCommits), | ||||
| // v123 -> v124 | |||||
| NewMigration("Add original informations for reactions", addReactionOriginals), | |||||
| } | } | ||||
| // Migrate database to current version | // Migrate database to current version | ||||
| @@ -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 | // IsGhost check if user is fake user for a deleted account | ||||
| func (u *User) IsGhost() bool { | func (u *User) IsGhost() bool { | ||||
| if u == nil { | if u == nil { | ||||
| @@ -16,5 +16,5 @@ type Comment struct { | |||||
| Created time.Time | Created time.Time | ||||
| Updated time.Time | Updated time.Time | ||||
| Content string | Content string | ||||
| Reactions *Reactions | |||||
| Reactions []*Reaction | |||||
| } | } | ||||
| @@ -22,5 +22,5 @@ type Issue struct { | |||||
| Updated time.Time | Updated time.Time | ||||
| Closed *time.Time | Closed *time.Time | ||||
| Labels []*Label | Labels []*Label | ||||
| Reactions *Reactions | |||||
| Reactions []*Reaction | |||||
| } | } | ||||
| @@ -33,6 +33,7 @@ type PullRequest struct { | |||||
| Assignee string | Assignee string | ||||
| Assignees []string | Assignees []string | ||||
| IsLocked bool | IsLocked bool | ||||
| Reactions []*Reaction | |||||
| } | } | ||||
| // IsForkPullRequest returns true if the pull request from a forked repository but not the same repository | // IsForkPullRequest returns true if the pull request from a forked repository but not the same repository | ||||
| @@ -1,17 +1,12 @@ | |||||
| // Copyright 2019 The Gitea Authors. All rights reserved. | |||||
| // Copyright 2018 Jonas Franz. All rights reserved. | |||||
| // Copyright 2020 The Gitea Authors. All rights reserved. | |||||
| // Use of this source code is governed by a MIT-style | // Use of this source code is governed by a MIT-style | ||||
| // license that can be found in the LICENSE file. | // license that can be found in the LICENSE file. | ||||
| package base | package base | ||||
| // Reactions represents a summary of reactions. | |||||
| type Reactions struct { | |||||
| TotalCount int | |||||
| PlusOne int | |||||
| MinusOne int | |||||
| Laugh int | |||||
| Confused int | |||||
| Heart int | |||||
| Hooray int | |||||
| // Reaction represents a reaction to an issue/pr/comment. | |||||
| type Reaction struct { | |||||
| UserID int64 | |||||
| UserName string | |||||
| Content string | |||||
| } | } | ||||
| @@ -361,7 +361,32 @@ func (g *GiteaLocalUploader) CreateIssues(issues ...*base.Issue) error { | |||||
| if issue.Closed != nil { | if issue.Closed != nil { | ||||
| is.ClosedUnix = timeutil.TimeStamp(issue.Closed.Unix()) | is.ClosedUnix = timeutil.TimeStamp(issue.Closed.Unix()) | ||||
| } | } | ||||
| // TODO: add reactions | |||||
| // add reactions | |||||
| for _, reaction := range issue.Reactions { | |||||
| userid, ok := g.userMap[reaction.UserID] | |||||
| if !ok && tp != "" { | |||||
| var err error | |||||
| userid, err = models.GetUserIDByExternalUserID(tp, fmt.Sprintf("%v", reaction.UserID)) | |||||
| if err != nil { | |||||
| log.Error("GetUserIDByExternalUserID: %v", err) | |||||
| } | |||||
| if userid > 0 { | |||||
| g.userMap[reaction.UserID] = userid | |||||
| } | |||||
| } | |||||
| var res = models.Reaction{ | |||||
| Type: reaction.Content, | |||||
| CreatedUnix: timeutil.TimeStampNow(), | |||||
| } | |||||
| if userid > 0 { | |||||
| res.UserID = userid | |||||
| } else { | |||||
| res.UserID = g.doer.ID | |||||
| res.OriginalAuthorID = reaction.UserID | |||||
| res.OriginalAuthor = reaction.UserName | |||||
| } | |||||
| is.Reactions = append(is.Reactions, &res) | |||||
| } | |||||
| iss = append(iss, &is) | iss = append(iss, &is) | ||||
| } | } | ||||
| @@ -420,9 +445,34 @@ func (g *GiteaLocalUploader) CreateComments(comments ...*base.Comment) error { | |||||
| cm.OriginalAuthorID = comment.PosterID | cm.OriginalAuthorID = comment.PosterID | ||||
| } | } | ||||
| cms = append(cms, &cm) | |||||
| // add reactions | |||||
| for _, reaction := range comment.Reactions { | |||||
| userid, ok := g.userMap[reaction.UserID] | |||||
| if !ok && tp != "" { | |||||
| var err error | |||||
| userid, err = models.GetUserIDByExternalUserID(tp, fmt.Sprintf("%v", reaction.UserID)) | |||||
| if err != nil { | |||||
| log.Error("GetUserIDByExternalUserID: %v", err) | |||||
| } | |||||
| if userid > 0 { | |||||
| g.userMap[reaction.UserID] = userid | |||||
| } | |||||
| } | |||||
| var res = models.Reaction{ | |||||
| Type: reaction.Content, | |||||
| CreatedUnix: timeutil.TimeStampNow(), | |||||
| } | |||||
| if userid > 0 { | |||||
| res.UserID = userid | |||||
| } else { | |||||
| res.UserID = g.doer.ID | |||||
| res.OriginalAuthorID = reaction.UserID | |||||
| res.OriginalAuthor = reaction.UserName | |||||
| } | |||||
| cm.Reactions = append(cm.Reactions, &res) | |||||
| } | |||||
| // TODO: Reactions | |||||
| cms = append(cms, &cm) | |||||
| } | } | ||||
| return models.InsertIssueComments(cms) | return models.InsertIssueComments(cms) | ||||
| @@ -581,10 +631,12 @@ func (g *GiteaLocalUploader) newPullRequest(pr *base.PullRequest) (*models.PullR | |||||
| UpdatedUnix: timeutil.TimeStamp(pr.Updated.Unix()), | UpdatedUnix: timeutil.TimeStamp(pr.Updated.Unix()), | ||||
| } | } | ||||
| tp := g.gitServiceType.Name() | |||||
| userid, ok := g.userMap[pr.PosterID] | userid, ok := g.userMap[pr.PosterID] | ||||
| if !ok { | |||||
| if !ok && tp != "" { | |||||
| var err error | var err error | ||||
| userid, err = models.GetUserIDByExternalUserID("github", fmt.Sprintf("%v", pr.PosterID)) | |||||
| userid, err = models.GetUserIDByExternalUserID(tp, fmt.Sprintf("%v", pr.PosterID)) | |||||
| if err != nil { | if err != nil { | ||||
| log.Error("GetUserIDByExternalUserID: %v", err) | log.Error("GetUserIDByExternalUserID: %v", err) | ||||
| } | } | ||||
| @@ -601,6 +653,33 @@ func (g *GiteaLocalUploader) newPullRequest(pr *base.PullRequest) (*models.PullR | |||||
| issue.OriginalAuthorID = pr.PosterID | issue.OriginalAuthorID = pr.PosterID | ||||
| } | } | ||||
| // add reactions | |||||
| for _, reaction := range pr.Reactions { | |||||
| userid, ok := g.userMap[reaction.UserID] | |||||
| if !ok && tp != "" { | |||||
| var err error | |||||
| userid, err = models.GetUserIDByExternalUserID(tp, fmt.Sprintf("%v", reaction.UserID)) | |||||
| if err != nil { | |||||
| log.Error("GetUserIDByExternalUserID: %v", err) | |||||
| } | |||||
| if userid > 0 { | |||||
| g.userMap[reaction.UserID] = userid | |||||
| } | |||||
| } | |||||
| var res = models.Reaction{ | |||||
| Type: reaction.Content, | |||||
| CreatedUnix: timeutil.TimeStampNow(), | |||||
| } | |||||
| if userid > 0 { | |||||
| res.UserID = userid | |||||
| } else { | |||||
| res.UserID = g.doer.ID | |||||
| res.OriginalAuthorID = reaction.UserID | |||||
| res.OriginalAuthor = reaction.UserName | |||||
| } | |||||
| issue.Reactions = append(issue.Reactions, &res) | |||||
| } | |||||
| var pullRequest = models.PullRequest{ | var pullRequest = models.PullRequest{ | ||||
| HeadRepoID: g.repo.ID, | HeadRepoID: g.repo.ID, | ||||
| HeadBranch: head, | HeadBranch: head, | ||||
| @@ -622,7 +701,6 @@ func (g *GiteaLocalUploader) newPullRequest(pr *base.PullRequest) (*models.PullR | |||||
| pullRequest.MergerID = g.doer.ID | pullRequest.MergerID = g.doer.ID | ||||
| } | } | ||||
| // TODO: reactions | |||||
| // TODO: assignees | // TODO: assignees | ||||
| return &pullRequest, nil | return &pullRequest, nil | ||||
| @@ -319,18 +319,6 @@ func (g *GithubDownloaderV3) GetReleases() ([]*base.Release, error) { | |||||
| return releases, nil | return releases, nil | ||||
| } | } | ||||
| func convertGithubReactions(reactions *github.Reactions) *base.Reactions { | |||||
| return &base.Reactions{ | |||||
| TotalCount: *reactions.TotalCount, | |||||
| PlusOne: *reactions.PlusOne, | |||||
| MinusOne: *reactions.MinusOne, | |||||
| Laugh: *reactions.Laugh, | |||||
| Confused: *reactions.Confused, | |||||
| Heart: *reactions.Heart, | |||||
| Hooray: *reactions.Hooray, | |||||
| } | |||||
| } | |||||
| // GetIssues returns issues according start and limit | // GetIssues returns issues according start and limit | ||||
| func (g *GithubDownloaderV3) GetIssues(page, perPage int) ([]*base.Issue, bool, error) { | func (g *GithubDownloaderV3) GetIssues(page, perPage int) ([]*base.Issue, bool, error) { | ||||
| opt := &github.IssueListByRepoOptions{ | opt := &github.IssueListByRepoOptions{ | ||||
| @@ -366,15 +354,36 @@ func (g *GithubDownloaderV3) GetIssues(page, perPage int) ([]*base.Issue, bool, | |||||
| for _, l := range issue.Labels { | for _, l := range issue.Labels { | ||||
| labels = append(labels, convertGithubLabel(&l)) | labels = append(labels, convertGithubLabel(&l)) | ||||
| } | } | ||||
| var reactions *base.Reactions | |||||
| if issue.Reactions != nil { | |||||
| reactions = convertGithubReactions(issue.Reactions) | |||||
| } | |||||
| var email string | var email string | ||||
| if issue.User.Email != nil { | if issue.User.Email != nil { | ||||
| email = *issue.User.Email | email = *issue.User.Email | ||||
| } | } | ||||
| // get reactions | |||||
| var reactions []*base.Reaction | |||||
| for i := 1; ; i++ { | |||||
| g.sleep() | |||||
| res, resp, err := g.client.Reactions.ListIssueReactions(g.ctx, g.repoOwner, g.repoName, issue.GetNumber(), &github.ListOptions{ | |||||
| Page: i, | |||||
| PerPage: perPage, | |||||
| }) | |||||
| if err != nil { | |||||
| return nil, false, err | |||||
| } | |||||
| g.rate = &resp.Rate | |||||
| if len(res) == 0 { | |||||
| break | |||||
| } | |||||
| for _, reaction := range res { | |||||
| reactions = append(reactions, &base.Reaction{ | |||||
| UserID: reaction.User.GetID(), | |||||
| UserName: reaction.User.GetLogin(), | |||||
| Content: reaction.GetContent(), | |||||
| }) | |||||
| } | |||||
| } | |||||
| allIssues = append(allIssues, &base.Issue{ | allIssues = append(allIssues, &base.Issue{ | ||||
| Title: *issue.Title, | Title: *issue.Title, | ||||
| Number: int64(*issue.Number), | Number: int64(*issue.Number), | ||||
| @@ -418,9 +427,29 @@ func (g *GithubDownloaderV3) GetComments(issueNumber int64) ([]*base.Comment, er | |||||
| if comment.User.Email != nil { | if comment.User.Email != nil { | ||||
| email = *comment.User.Email | email = *comment.User.Email | ||||
| } | } | ||||
| var reactions *base.Reactions | |||||
| if comment.Reactions != nil { | |||||
| reactions = convertGithubReactions(comment.Reactions) | |||||
| // get reactions | |||||
| var reactions []*base.Reaction | |||||
| for i := 1; ; i++ { | |||||
| g.sleep() | |||||
| res, resp, err := g.client.Reactions.ListIssueCommentReactions(g.ctx, g.repoOwner, g.repoName, comment.GetID(), &github.ListOptions{ | |||||
| Page: i, | |||||
| PerPage: 100, | |||||
| }) | |||||
| if err != nil { | |||||
| return nil, err | |||||
| } | |||||
| g.rate = &resp.Rate | |||||
| if len(res) == 0 { | |||||
| break | |||||
| } | |||||
| for _, reaction := range res { | |||||
| reactions = append(reactions, &base.Reaction{ | |||||
| UserID: reaction.User.GetID(), | |||||
| UserName: reaction.User.GetLogin(), | |||||
| Content: reaction.GetContent(), | |||||
| }) | |||||
| } | |||||
| } | } | ||||
| allComments = append(allComments, &base.Comment{ | allComments = append(allComments, &base.Comment{ | ||||
| IssueIndex: issueNumber, | IssueIndex: issueNumber, | ||||
| @@ -473,8 +502,6 @@ func (g *GithubDownloaderV3) GetPullRequests(page, perPage int) ([]*base.PullReq | |||||
| labels = append(labels, convertGithubLabel(l)) | labels = append(labels, convertGithubLabel(l)) | ||||
| } | } | ||||
| // FIXME: This API missing reactions, we may need another extra request to get reactions | |||||
| var email string | var email string | ||||
| if pr.User.Email != nil { | if pr.User.Email != nil { | ||||
| email = *pr.User.Email | email = *pr.User.Email | ||||
| @@ -515,6 +542,30 @@ func (g *GithubDownloaderV3) GetPullRequests(page, perPage int) ([]*base.PullReq | |||||
| headUserName = *pr.Head.User.Login | headUserName = *pr.Head.User.Login | ||||
| } | } | ||||
| // get reactions | |||||
| var reactions []*base.Reaction | |||||
| for i := 1; ; i++ { | |||||
| g.sleep() | |||||
| res, resp, err := g.client.Reactions.ListIssueReactions(g.ctx, g.repoOwner, g.repoName, pr.GetNumber(), &github.ListOptions{ | |||||
| Page: i, | |||||
| PerPage: perPage, | |||||
| }) | |||||
| if err != nil { | |||||
| return nil, err | |||||
| } | |||||
| g.rate = &resp.Rate | |||||
| if len(res) == 0 { | |||||
| break | |||||
| } | |||||
| for _, reaction := range res { | |||||
| reactions = append(reactions, &base.Reaction{ | |||||
| UserID: reaction.User.GetID(), | |||||
| UserName: reaction.User.GetLogin(), | |||||
| Content: reaction.GetContent(), | |||||
| }) | |||||
| } | |||||
| } | |||||
| allPRs = append(allPRs, &base.PullRequest{ | allPRs = append(allPRs, &base.PullRequest{ | ||||
| Title: *pr.Title, | Title: *pr.Title, | ||||
| Number: int64(*pr.Number), | Number: int64(*pr.Number), | ||||
| @@ -545,7 +596,8 @@ func (g *GithubDownloaderV3) GetPullRequests(page, perPage int) ([]*base.PullReq | |||||
| RepoName: *pr.Base.Repo.Name, | RepoName: *pr.Base.Repo.Name, | ||||
| OwnerName: *pr.Base.User.Login, | OwnerName: *pr.Base.User.Login, | ||||
| }, | }, | ||||
| PatchURL: *pr.PatchURL, | |||||
| PatchURL: *pr.PatchURL, | |||||
| Reactions: reactions, | |||||
| }) | }) | ||||
| } | } | ||||
| @@ -170,14 +170,12 @@ func TestGitHubDownloadRepo(t *testing.T) { | |||||
| Description: "Good for newcomers", | Description: "Good for newcomers", | ||||
| }, | }, | ||||
| }, | }, | ||||
| Reactions: &base.Reactions{ | |||||
| TotalCount: 1, | |||||
| PlusOne: 1, | |||||
| MinusOne: 0, | |||||
| Laugh: 0, | |||||
| Confused: 0, | |||||
| Heart: 0, | |||||
| Hooray: 0, | |||||
| Reactions: []*base.Reaction{ | |||||
| { | |||||
| UserID: 1669571, | |||||
| UserName: "mrsdizzie", | |||||
| Content: "+1", | |||||
| }, | |||||
| }, | }, | ||||
| Closed: &closed1, | Closed: &closed1, | ||||
| }, | }, | ||||
| @@ -198,14 +196,37 @@ func TestGitHubDownloadRepo(t *testing.T) { | |||||
| Description: "This issue or pull request already exists", | Description: "This issue or pull request already exists", | ||||
| }, | }, | ||||
| }, | }, | ||||
| Reactions: &base.Reactions{ | |||||
| TotalCount: 6, | |||||
| PlusOne: 1, | |||||
| MinusOne: 1, | |||||
| Laugh: 1, | |||||
| Confused: 1, | |||||
| Heart: 1, | |||||
| Hooray: 1, | |||||
| Reactions: []*base.Reaction{ | |||||
| { | |||||
| UserID: 1669571, | |||||
| UserName: "mrsdizzie", | |||||
| Content: "heart", | |||||
| }, | |||||
| { | |||||
| UserID: 1669571, | |||||
| UserName: "mrsdizzie", | |||||
| Content: "laugh", | |||||
| }, | |||||
| { | |||||
| UserID: 1669571, | |||||
| UserName: "mrsdizzie", | |||||
| Content: "-1", | |||||
| }, | |||||
| { | |||||
| UserID: 1669571, | |||||
| UserName: "mrsdizzie", | |||||
| Content: "confused", | |||||
| }, | |||||
| { | |||||
| UserID: 1669571, | |||||
| UserName: "mrsdizzie", | |||||
| Content: "hooray", | |||||
| }, | |||||
| { | |||||
| UserID: 1669571, | |||||
| UserName: "mrsdizzie", | |||||
| Content: "+1", | |||||
| }, | |||||
| }, | }, | ||||
| Closed: &closed2, | Closed: &closed2, | ||||
| }, | }, | ||||
| @@ -223,14 +244,12 @@ func TestGitHubDownloadRepo(t *testing.T) { | |||||
| Created: time.Date(2019, 11, 12, 21, 0, 13, 0, time.UTC), | Created: time.Date(2019, 11, 12, 21, 0, 13, 0, time.UTC), | ||||
| Updated: time.Date(2019, 11, 12, 21, 0, 13, 0, time.UTC), | Updated: time.Date(2019, 11, 12, 21, 0, 13, 0, time.UTC), | ||||
| Content: "This is a comment", | Content: "This is a comment", | ||||
| Reactions: &base.Reactions{ | |||||
| TotalCount: 1, | |||||
| PlusOne: 1, | |||||
| MinusOne: 0, | |||||
| Laugh: 0, | |||||
| Confused: 0, | |||||
| Heart: 0, | |||||
| Hooray: 0, | |||||
| Reactions: []*base.Reaction{ | |||||
| { | |||||
| UserID: 1669571, | |||||
| UserName: "mrsdizzie", | |||||
| Content: "+1", | |||||
| }, | |||||
| }, | }, | ||||
| }, | }, | ||||
| { | { | ||||
| @@ -240,15 +259,7 @@ func TestGitHubDownloadRepo(t *testing.T) { | |||||
| Created: time.Date(2019, 11, 12, 22, 7, 14, 0, time.UTC), | Created: time.Date(2019, 11, 12, 22, 7, 14, 0, time.UTC), | ||||
| Updated: time.Date(2019, 11, 12, 22, 7, 14, 0, time.UTC), | Updated: time.Date(2019, 11, 12, 22, 7, 14, 0, time.UTC), | ||||
| Content: "A second comment", | Content: "A second comment", | ||||
| Reactions: &base.Reactions{ | |||||
| TotalCount: 0, | |||||
| PlusOne: 0, | |||||
| MinusOne: 0, | |||||
| Laugh: 0, | |||||
| Confused: 0, | |||||
| Heart: 0, | |||||
| Hooray: 0, | |||||
| }, | |||||
| Reactions: nil, | |||||
| }, | }, | ||||
| }, comments[:2]) | }, comments[:2]) | ||||
| @@ -331,6 +342,18 @@ func TestGitHubDownloadRepo(t *testing.T) { | |||||
| }, | }, | ||||
| Merged: false, | Merged: false, | ||||
| MergeCommitSHA: "565d1208f5fffdc1c5ae1a2436491eb9a5e4ebae", | MergeCommitSHA: "565d1208f5fffdc1c5ae1a2436491eb9a5e4ebae", | ||||
| Reactions: []*base.Reaction{ | |||||
| { | |||||
| UserID: 81045, | |||||
| UserName: "lunny", | |||||
| Content: "heart", | |||||
| }, | |||||
| { | |||||
| UserID: 81045, | |||||
| UserName: "lunny", | |||||
| Content: "+1", | |||||
| }, | |||||
| }, | |||||
| }, | }, | ||||
| }, prs) | }, prs) | ||||
| } | } | ||||
| @@ -65,7 +65,7 @@ func GetIssueCommentReactions(ctx *context.APIContext) { | |||||
| ctx.Error(http.StatusInternalServerError, "FindIssueReactions", err) | ctx.Error(http.StatusInternalServerError, "FindIssueReactions", err) | ||||
| return | return | ||||
| } | } | ||||
| _, err = reactions.LoadUsers() | |||||
| _, err = reactions.LoadUsers(ctx.Repo.Repository) | |||||
| if err != nil { | if err != nil { | ||||
| ctx.Error(http.StatusInternalServerError, "ReactionList.LoadUsers()", err) | ctx.Error(http.StatusInternalServerError, "ReactionList.LoadUsers()", err) | ||||
| return | return | ||||
| @@ -271,7 +271,7 @@ func GetIssueReactions(ctx *context.APIContext) { | |||||
| ctx.Error(http.StatusInternalServerError, "FindIssueReactions", err) | ctx.Error(http.StatusInternalServerError, "FindIssueReactions", err) | ||||
| return | return | ||||
| } | } | ||||
| _, err = reactions.LoadUsers() | |||||
| _, err = reactions.LoadUsers(ctx.Repo.Repository) | |||||
| if err != nil { | if err != nil { | ||||
| ctx.Error(http.StatusInternalServerError, "ReactionList.LoadUsers()", err) | ctx.Error(http.StatusInternalServerError, "ReactionList.LoadUsers()", err) | ||||
| return | return | ||||
| @@ -1608,7 +1608,7 @@ func ChangeCommentReaction(ctx *context.Context, form auth.ReactionForm) { | |||||
| } | } | ||||
| // Reload new reactions | // Reload new reactions | ||||
| comment.Reactions = nil | comment.Reactions = nil | ||||
| if err = comment.LoadReactions(); err != nil { | |||||
| if err = comment.LoadReactions(ctx.Repo.Repository); err != nil { | |||||
| log.Info("comment.LoadReactions: %s", err) | log.Info("comment.LoadReactions: %s", err) | ||||
| break | break | ||||
| } | } | ||||
| @@ -1622,7 +1622,7 @@ func ChangeCommentReaction(ctx *context.Context, form auth.ReactionForm) { | |||||
| // Reload new reactions | // Reload new reactions | ||||
| comment.Reactions = nil | comment.Reactions = nil | ||||
| if err = comment.LoadReactions(); err != nil { | |||||
| if err = comment.LoadReactions(ctx.Repo.Repository); err != nil { | |||||
| log.Info("comment.LoadReactions: %s", err) | log.Info("comment.LoadReactions: %s", err) | ||||
| break | break | ||||
| } | } | ||||