mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-10-26 12:27:06 +00:00 
			
		
		
		
	Move reaction to models/issues/ (#19264)
* Move reaction to models/issues/ * Fix test * move the function * improve code * Update models/issues/reaction.go Co-authored-by: wxiaoguang <wxiaoguang@gmail.com> Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
This commit is contained in:
		| @@ -10,6 +10,7 @@ import ( | |||||||
| 	"code.gitea.io/gitea/models/db" | 	"code.gitea.io/gitea/models/db" | ||||||
| 	repo_model "code.gitea.io/gitea/models/repo" | 	repo_model "code.gitea.io/gitea/models/repo" | ||||||
| 	user_model "code.gitea.io/gitea/models/user" | 	user_model "code.gitea.io/gitea/models/user" | ||||||
|  | 	"code.gitea.io/gitea/modules/container" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| // ActionList defines a list of actions | // ActionList defines a list of actions | ||||||
| @@ -22,7 +23,7 @@ func (actions ActionList) getUserIDs() []int64 { | |||||||
| 			userIDs[action.ActUserID] = struct{}{} | 			userIDs[action.ActUserID] = struct{}{} | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	return keysInt64(userIDs) | 	return container.KeysInt64(userIDs) | ||||||
| } | } | ||||||
|  |  | ||||||
| func (actions ActionList) loadUsers(e db.Engine) (map[int64]*user_model.User, error) { | func (actions ActionList) loadUsers(e db.Engine) (map[int64]*user_model.User, error) { | ||||||
| @@ -52,7 +53,7 @@ func (actions ActionList) getRepoIDs() []int64 { | |||||||
| 			repoIDs[action.RepoID] = struct{}{} | 			repoIDs[action.RepoID] = struct{}{} | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	return keysInt64(repoIDs) | 	return container.KeysInt64(repoIDs) | ||||||
| } | } | ||||||
|  |  | ||||||
| func (actions ActionList) loadRepositories(e db.Engine) error { | func (actions ActionList) loadRepositories(e db.Engine) error { | ||||||
|   | |||||||
| @@ -765,36 +765,6 @@ func (err ErrPullWasClosed) Error() string { | |||||||
| 	return fmt.Sprintf("Pull request [%d] %d was already closed", err.ID, err.Index) | 	return fmt.Sprintf("Pull request [%d] %d was already closed", err.ID, err.Index) | ||||||
| } | } | ||||||
|  |  | ||||||
| // ErrForbiddenIssueReaction is used when a forbidden reaction was try to created |  | ||||||
| type ErrForbiddenIssueReaction struct { |  | ||||||
| 	Reaction string |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // IsErrForbiddenIssueReaction checks if an error is a ErrForbiddenIssueReaction. |  | ||||||
| func IsErrForbiddenIssueReaction(err error) bool { |  | ||||||
| 	_, ok := err.(ErrForbiddenIssueReaction) |  | ||||||
| 	return ok |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (err ErrForbiddenIssueReaction) Error() string { |  | ||||||
| 	return fmt.Sprintf("'%s' is not an allowed reaction", err.Reaction) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // ErrReactionAlreadyExist is used when a existing reaction was try to created |  | ||||||
| type ErrReactionAlreadyExist struct { |  | ||||||
| 	Reaction string |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // IsErrReactionAlreadyExist checks if an error is a ErrReactionAlreadyExist. |  | ||||||
| func IsErrReactionAlreadyExist(err error) bool { |  | ||||||
| 	_, ok := err.(ErrReactionAlreadyExist) |  | ||||||
| 	return ok |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (err ErrReactionAlreadyExist) Error() string { |  | ||||||
| 	return fmt.Sprintf("reaction '%s' already exists", err.Reaction) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // __________      .__  .__ __________                                     __ | // __________      .__  .__ __________                                     __ | ||||||
| // \______   \__ __|  | |  |\______   \ ____  ________ __   ____   _______/  |_ | // \______   \__ __|  | |  |\______   \ ____  ________ __   ____   _______/  |_ | ||||||
| //  |     ___/  |  \  | |  | |       _// __ \/ ____/  |  \_/ __ \ /  ___/\   __\ | //  |     ___/  |  \  | |  | |       _// __ \/ ____/  |  \_/ __ \ /  ___/\   __\ | ||||||
|   | |||||||
| @@ -6,17 +6,8 @@ package models | |||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	repo_model "code.gitea.io/gitea/models/repo" | 	repo_model "code.gitea.io/gitea/models/repo" | ||||||
| 	user_model "code.gitea.io/gitea/models/user" |  | ||||||
| ) | ) | ||||||
|  |  | ||||||
| func keysInt64(m map[int64]struct{}) []int64 { |  | ||||||
| 	keys := make([]int64, 0, len(m)) |  | ||||||
| 	for k := range m { |  | ||||||
| 		keys = append(keys, k) |  | ||||||
| 	} |  | ||||||
| 	return keys |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func valuesRepository(m map[int64]*repo_model.Repository) []*repo_model.Repository { | func valuesRepository(m map[int64]*repo_model.Repository) []*repo_model.Repository { | ||||||
| 	values := make([]*repo_model.Repository, 0, len(m)) | 	values := make([]*repo_model.Repository, 0, len(m)) | ||||||
| 	for _, v := range m { | 	for _, v := range m { | ||||||
| @@ -24,11 +15,3 @@ func valuesRepository(m map[int64]*repo_model.Repository) []*repo_model.Reposito | |||||||
| 	} | 	} | ||||||
| 	return values | 	return values | ||||||
| } | } | ||||||
|  |  | ||||||
| func valuesUser(m map[int64]*user_model.User) []*user_model.User { |  | ||||||
| 	values := make([]*user_model.User, 0, len(m)) |  | ||||||
| 	for _, v := range m { |  | ||||||
| 		values = append(values, v) |  | ||||||
| 	} |  | ||||||
| 	return values |  | ||||||
| } |  | ||||||
|   | |||||||
| @@ -72,7 +72,7 @@ type Issue struct { | |||||||
|  |  | ||||||
| 	Attachments      []*repo_model.Attachment           `xorm:"-"` | 	Attachments      []*repo_model.Attachment           `xorm:"-"` | ||||||
| 	Comments         []*Comment                         `xorm:"-"` | 	Comments         []*Comment                         `xorm:"-"` | ||||||
| 	Reactions        ReactionList                       `xorm:"-"` | 	Reactions        issues.ReactionList                `xorm:"-"` | ||||||
| 	TotalTrackedTime int64                              `xorm:"-"` | 	TotalTrackedTime int64                              `xorm:"-"` | ||||||
| 	Assignees        []*user_model.User                 `xorm:"-"` | 	Assignees        []*user_model.User                 `xorm:"-"` | ||||||
| 	ForeignReference *foreignreference.ForeignReference `xorm:"-"` | 	ForeignReference *foreignreference.ForeignReference `xorm:"-"` | ||||||
| @@ -244,8 +244,7 @@ func (issue *Issue) loadReactions(ctx context.Context) (err error) { | |||||||
| 	if issue.Reactions != nil { | 	if issue.Reactions != nil { | ||||||
| 		return nil | 		return nil | ||||||
| 	} | 	} | ||||||
| 	e := db.GetEngine(ctx) | 	reactions, _, err := issues.FindReactions(ctx, issues.FindReactionsOptions{ | ||||||
| 	reactions, _, err := findReactions(e, FindReactionsOptions{ |  | ||||||
| 		IssueID: issue.ID, | 		IssueID: issue.ID, | ||||||
| 	}) | 	}) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| @@ -255,7 +254,7 @@ func (issue *Issue) loadReactions(ctx context.Context) (err error) { | |||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
| 	// Load reaction user data | 	// Load reaction user data | ||||||
| 	if _, err := ReactionList(reactions).loadUsers(e, issue.Repo); err != nil { | 	if _, err := issues.ReactionList(reactions).LoadUsers(ctx, issue.Repo); err != nil { | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @@ -2111,7 +2110,7 @@ func deleteIssue(ctx context.Context, issue *Issue) error { | |||||||
| 		&IssueAssignees{}, | 		&IssueAssignees{}, | ||||||
| 		&IssueUser{}, | 		&IssueUser{}, | ||||||
| 		&Notification{}, | 		&Notification{}, | ||||||
| 		&Reaction{}, | 		&issues.Reaction{}, | ||||||
| 		&IssueWatch{}, | 		&IssueWatch{}, | ||||||
| 		&Stopwatch{}, | 		&Stopwatch{}, | ||||||
| 		&TrackedTime{}, | 		&TrackedTime{}, | ||||||
| @@ -2429,7 +2428,7 @@ func deleteIssuesByRepoID(sess db.Engine, repoID int64) (attachmentPaths []strin | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if _, err = sess.In("issue_id", deleteCond). | 	if _, err = sess.In("issue_id", deleteCond). | ||||||
| 		Delete(&Reaction{}); err != nil { | 		Delete(&issues.Reaction{}); err != nil { | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|   | |||||||
| @@ -244,7 +244,7 @@ type Comment struct { | |||||||
| 	CommitSHA string `xorm:"VARCHAR(40)"` | 	CommitSHA string `xorm:"VARCHAR(40)"` | ||||||
|  |  | ||||||
| 	Attachments []*repo_model.Attachment `xorm:"-"` | 	Attachments []*repo_model.Attachment `xorm:"-"` | ||||||
| 	Reactions   ReactionList             `xorm:"-"` | 	Reactions   issues.ReactionList      `xorm:"-"` | ||||||
|  |  | ||||||
| 	// For view issue page. | 	// For view issue page. | ||||||
| 	ShowRole RoleDescriptor `xorm:"-"` | 	ShowRole RoleDescriptor `xorm:"-"` | ||||||
| @@ -631,11 +631,11 @@ func (c *Comment) LoadTime() error { | |||||||
| 	return err | 	return err | ||||||
| } | } | ||||||
|  |  | ||||||
| func (c *Comment) loadReactions(e db.Engine, repo *repo_model.Repository) (err error) { | func (c *Comment) loadReactions(ctx context.Context, repo *repo_model.Repository) (err error) { | ||||||
| 	if c.Reactions != nil { | 	if c.Reactions != nil { | ||||||
| 		return nil | 		return nil | ||||||
| 	} | 	} | ||||||
| 	c.Reactions, _, err = findReactions(e, FindReactionsOptions{ | 	c.Reactions, _, err = issues.FindReactions(ctx, issues.FindReactionsOptions{ | ||||||
| 		IssueID:   c.IssueID, | 		IssueID:   c.IssueID, | ||||||
| 		CommentID: c.ID, | 		CommentID: c.ID, | ||||||
| 	}) | 	}) | ||||||
| @@ -643,7 +643,7 @@ func (c *Comment) loadReactions(e db.Engine, repo *repo_model.Repository) (err e | |||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
| 	// Load reaction user data | 	// Load reaction user data | ||||||
| 	if _, err := c.Reactions.loadUsers(e, repo); err != nil { | 	if _, err := c.Reactions.LoadUsers(ctx, repo); err != nil { | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
| 	return nil | 	return nil | ||||||
| @@ -651,7 +651,7 @@ func (c *Comment) loadReactions(e db.Engine, repo *repo_model.Repository) (err e | |||||||
|  |  | ||||||
| // LoadReactions loads comment reactions | // LoadReactions loads comment reactions | ||||||
| func (c *Comment) LoadReactions(repo *repo_model.Repository) error { | func (c *Comment) LoadReactions(repo *repo_model.Repository) error { | ||||||
| 	return c.loadReactions(db.GetEngine(db.DefaultContext), repo) | 	return c.loadReactions(db.DefaultContext, repo) | ||||||
| } | } | ||||||
|  |  | ||||||
| func (c *Comment) loadReview(e db.Engine) (err error) { | func (c *Comment) loadReview(e db.Engine) (err error) { | ||||||
| @@ -1146,14 +1146,15 @@ func DeleteComment(comment *Comment) error { | |||||||
| 	} | 	} | ||||||
| 	defer committer.Close() | 	defer committer.Close() | ||||||
|  |  | ||||||
| 	if err := deleteComment(db.GetEngine(ctx), comment); err != nil { | 	if err := deleteComment(ctx, comment); err != nil { | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	return committer.Commit() | 	return committer.Commit() | ||||||
| } | } | ||||||
|  |  | ||||||
| func deleteComment(e db.Engine, comment *Comment) error { | func deleteComment(ctx context.Context, comment *Comment) error { | ||||||
|  | 	e := db.GetEngine(ctx) | ||||||
| 	if _, err := e.ID(comment.ID).NoAutoCondition().Delete(comment); err != nil { | 	if _, err := e.ID(comment.ID).NoAutoCondition().Delete(comment); err != nil { | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
| @@ -1177,7 +1178,7 @@ func deleteComment(e db.Engine, comment *Comment) error { | |||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	return deleteReaction(e, &ReactionOptions{Comment: comment}) | 	return issues.DeleteReaction(ctx, &issues.ReactionOptions{CommentID: comment.ID}) | ||||||
| } | } | ||||||
|  |  | ||||||
| // CodeComments represents comments on code by using this structure: FILENAME -> LINE (+ == proposed; - == previous) -> COMMENTS | // CodeComments represents comments on code by using this structure: FILENAME -> LINE (+ == proposed; - == previous) -> COMMENTS | ||||||
|   | |||||||
| @@ -10,6 +10,7 @@ import ( | |||||||
| 	"code.gitea.io/gitea/models/db" | 	"code.gitea.io/gitea/models/db" | ||||||
| 	repo_model "code.gitea.io/gitea/models/repo" | 	repo_model "code.gitea.io/gitea/models/repo" | ||||||
| 	user_model "code.gitea.io/gitea/models/user" | 	user_model "code.gitea.io/gitea/models/user" | ||||||
|  | 	"code.gitea.io/gitea/modules/container" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| // CommentList defines a list of comments | // CommentList defines a list of comments | ||||||
| @@ -22,7 +23,7 @@ func (comments CommentList) getPosterIDs() []int64 { | |||||||
| 			posterIDs[comment.PosterID] = struct{}{} | 			posterIDs[comment.PosterID] = struct{}{} | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	return keysInt64(posterIDs) | 	return container.KeysInt64(posterIDs) | ||||||
| } | } | ||||||
|  |  | ||||||
| func (comments CommentList) loadPosters(e db.Engine) error { | func (comments CommentList) loadPosters(e db.Engine) error { | ||||||
| @@ -75,7 +76,7 @@ func (comments CommentList) getLabelIDs() []int64 { | |||||||
| 			ids[comment.LabelID] = struct{}{} | 			ids[comment.LabelID] = struct{}{} | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	return keysInt64(ids) | 	return container.KeysInt64(ids) | ||||||
| } | } | ||||||
|  |  | ||||||
| func (comments CommentList) loadLabels(e db.Engine) error { | func (comments CommentList) loadLabels(e db.Engine) error { | ||||||
| @@ -125,7 +126,7 @@ func (comments CommentList) getMilestoneIDs() []int64 { | |||||||
| 			ids[comment.MilestoneID] = struct{}{} | 			ids[comment.MilestoneID] = struct{}{} | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	return keysInt64(ids) | 	return container.KeysInt64(ids) | ||||||
| } | } | ||||||
|  |  | ||||||
| func (comments CommentList) loadMilestones(e db.Engine) error { | func (comments CommentList) loadMilestones(e db.Engine) error { | ||||||
| @@ -168,7 +169,7 @@ func (comments CommentList) getOldMilestoneIDs() []int64 { | |||||||
| 			ids[comment.OldMilestoneID] = struct{}{} | 			ids[comment.OldMilestoneID] = struct{}{} | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	return keysInt64(ids) | 	return container.KeysInt64(ids) | ||||||
| } | } | ||||||
|  |  | ||||||
| func (comments CommentList) loadOldMilestones(e db.Engine) error { | func (comments CommentList) loadOldMilestones(e db.Engine) error { | ||||||
| @@ -211,7 +212,7 @@ func (comments CommentList) getAssigneeIDs() []int64 { | |||||||
| 			ids[comment.AssigneeID] = struct{}{} | 			ids[comment.AssigneeID] = struct{}{} | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	return keysInt64(ids) | 	return container.KeysInt64(ids) | ||||||
| } | } | ||||||
|  |  | ||||||
| func (comments CommentList) loadAssignees(e db.Engine) error { | func (comments CommentList) loadAssignees(e db.Engine) error { | ||||||
| @@ -267,7 +268,7 @@ func (comments CommentList) getIssueIDs() []int64 { | |||||||
| 			ids[comment.IssueID] = struct{}{} | 			ids[comment.IssueID] = struct{}{} | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	return keysInt64(ids) | 	return container.KeysInt64(ids) | ||||||
| } | } | ||||||
|  |  | ||||||
| // Issues returns all the issues of comments | // Issues returns all the issues of comments | ||||||
| @@ -342,7 +343,7 @@ func (comments CommentList) getDependentIssueIDs() []int64 { | |||||||
| 			ids[comment.DependentIssueID] = struct{}{} | 			ids[comment.DependentIssueID] = struct{}{} | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	return keysInt64(ids) | 	return container.KeysInt64(ids) | ||||||
| } | } | ||||||
|  |  | ||||||
| func (comments CommentList) loadDependentIssues(ctx context.Context) error { | func (comments CommentList) loadDependentIssues(ctx context.Context) error { | ||||||
| @@ -444,7 +445,7 @@ func (comments CommentList) getReviewIDs() []int64 { | |||||||
| 			ids[comment.ReviewID] = struct{}{} | 			ids[comment.ReviewID] = struct{}{} | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	return keysInt64(ids) | 	return container.KeysInt64(ids) | ||||||
| } | } | ||||||
|  |  | ||||||
| func (comments CommentList) loadReviews(e db.Engine) error { | func (comments CommentList) loadReviews(e db.Engine) error { | ||||||
|   | |||||||
| @@ -10,6 +10,7 @@ import ( | |||||||
| 	"code.gitea.io/gitea/models/db" | 	"code.gitea.io/gitea/models/db" | ||||||
| 	repo_model "code.gitea.io/gitea/models/repo" | 	repo_model "code.gitea.io/gitea/models/repo" | ||||||
| 	user_model "code.gitea.io/gitea/models/user" | 	user_model "code.gitea.io/gitea/models/user" | ||||||
|  | 	"code.gitea.io/gitea/modules/container" | ||||||
|  |  | ||||||
| 	"xorm.io/builder" | 	"xorm.io/builder" | ||||||
| ) | ) | ||||||
| @@ -32,7 +33,7 @@ func (issues IssueList) getRepoIDs() []int64 { | |||||||
| 			repoIDs[issue.RepoID] = struct{}{} | 			repoIDs[issue.RepoID] = struct{}{} | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	return keysInt64(repoIDs) | 	return container.KeysInt64(repoIDs) | ||||||
| } | } | ||||||
|  |  | ||||||
| func (issues IssueList) loadRepositories(e db.Engine) ([]*repo_model.Repository, error) { | func (issues IssueList) loadRepositories(e db.Engine) ([]*repo_model.Repository, error) { | ||||||
| @@ -83,7 +84,7 @@ func (issues IssueList) getPosterIDs() []int64 { | |||||||
| 			posterIDs[issue.PosterID] = struct{}{} | 			posterIDs[issue.PosterID] = struct{}{} | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	return keysInt64(posterIDs) | 	return container.KeysInt64(posterIDs) | ||||||
| } | } | ||||||
|  |  | ||||||
| func (issues IssueList) loadPosters(e db.Engine) error { | func (issues IssueList) loadPosters(e db.Engine) error { | ||||||
| @@ -189,7 +190,7 @@ func (issues IssueList) getMilestoneIDs() []int64 { | |||||||
| 			ids[issue.MilestoneID] = struct{}{} | 			ids[issue.MilestoneID] = struct{}{} | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	return keysInt64(ids) | 	return container.KeysInt64(ids) | ||||||
| } | } | ||||||
|  |  | ||||||
| func (issues IssueList) loadMilestones(e db.Engine) error { | func (issues IssueList) loadMilestones(e db.Engine) error { | ||||||
|   | |||||||
| @@ -9,8 +9,18 @@ import ( | |||||||
| 	"testing" | 	"testing" | ||||||
|  |  | ||||||
| 	"code.gitea.io/gitea/models/unittest" | 	"code.gitea.io/gitea/models/unittest" | ||||||
|  | 	"code.gitea.io/gitea/modules/setting" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| func TestMain(m *testing.M) { | func init() { | ||||||
| 	unittest.MainTest(m, filepath.Join("..", ".."), "") | 	setting.SetCustomPathAndConf("", "", "") | ||||||
|  | 	setting.LoadForTest() | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func TestMain(m *testing.M) { | ||||||
|  | 	unittest.MainTest(m, filepath.Join("..", ".."), | ||||||
|  | 		"reaction.yml", | ||||||
|  | 		"user.yml", | ||||||
|  | 		"repository.yml", | ||||||
|  | 	) | ||||||
| } | } | ||||||
|   | |||||||
| @@ -2,21 +2,53 @@ | |||||||
| // 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 models | package issues | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"bytes" | 	"bytes" | ||||||
|  | 	"context" | ||||||
| 	"fmt" | 	"fmt" | ||||||
| 
 | 
 | ||||||
| 	"code.gitea.io/gitea/models/db" | 	"code.gitea.io/gitea/models/db" | ||||||
| 	repo_model "code.gitea.io/gitea/models/repo" | 	repo_model "code.gitea.io/gitea/models/repo" | ||||||
| 	user_model "code.gitea.io/gitea/models/user" | 	user_model "code.gitea.io/gitea/models/user" | ||||||
|  | 	"code.gitea.io/gitea/modules/container" | ||||||
| 	"code.gitea.io/gitea/modules/setting" | 	"code.gitea.io/gitea/modules/setting" | ||||||
| 	"code.gitea.io/gitea/modules/timeutil" | 	"code.gitea.io/gitea/modules/timeutil" | ||||||
| 
 | 
 | ||||||
| 	"xorm.io/builder" | 	"xorm.io/builder" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
|  | // ErrForbiddenIssueReaction is used when a forbidden reaction was try to created | ||||||
|  | type ErrForbiddenIssueReaction struct { | ||||||
|  | 	Reaction string | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // IsErrForbiddenIssueReaction checks if an error is a ErrForbiddenIssueReaction. | ||||||
|  | func IsErrForbiddenIssueReaction(err error) bool { | ||||||
|  | 	_, ok := err.(ErrForbiddenIssueReaction) | ||||||
|  | 	return ok | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (err ErrForbiddenIssueReaction) Error() string { | ||||||
|  | 	return fmt.Sprintf("'%s' is not an allowed reaction", err.Reaction) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // ErrReactionAlreadyExist is used when a existing reaction was try to created | ||||||
|  | type ErrReactionAlreadyExist struct { | ||||||
|  | 	Reaction string | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // IsErrReactionAlreadyExist checks if an error is a ErrReactionAlreadyExist. | ||||||
|  | func IsErrReactionAlreadyExist(err error) bool { | ||||||
|  | 	_, ok := err.(ErrReactionAlreadyExist) | ||||||
|  | 	return ok | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (err ErrReactionAlreadyExist) Error() string { | ||||||
|  | 	return fmt.Sprintf("reaction '%s' already exists", err.Reaction) | ||||||
|  | } | ||||||
|  | 
 | ||||||
| // 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"` | 	ID               int64              `xorm:"pk autoincr"` | ||||||
| @@ -30,6 +62,36 @@ type Reaction struct { | |||||||
| 	CreatedUnix      timeutil.TimeStamp `xorm:"INDEX created"` | 	CreatedUnix      timeutil.TimeStamp `xorm:"INDEX created"` | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | // LoadUser load user of reaction | ||||||
|  | func (r *Reaction) LoadUser() (*user_model.User, error) { | ||||||
|  | 	if r.User != nil { | ||||||
|  | 		return r.User, nil | ||||||
|  | 	} | ||||||
|  | 	user, err := user_model.GetUserByIDCtx(db.DefaultContext, r.UserID) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	r.User = user | ||||||
|  | 	return user, nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // RemapExternalUser ExternalUserRemappable interface | ||||||
|  | func (r *Reaction) RemapExternalUser(externalName string, externalID, userID int64) error { | ||||||
|  | 	r.OriginalAuthor = externalName | ||||||
|  | 	r.OriginalAuthorID = externalID | ||||||
|  | 	r.UserID = userID | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // GetUserID ExternalUserRemappable interface | ||||||
|  | func (r *Reaction) GetUserID() int64 { return r.UserID } | ||||||
|  | 
 | ||||||
|  | // GetExternalName ExternalUserRemappable interface | ||||||
|  | func (r *Reaction) GetExternalName() string { return r.OriginalAuthor } | ||||||
|  | 
 | ||||||
|  | // GetExternalID ExternalUserRemappable interface | ||||||
|  | func (r *Reaction) GetExternalID() int64 { return r.OriginalAuthorID } | ||||||
|  | 
 | ||||||
| func init() { | func init() { | ||||||
| 	db.RegisterModel(new(Reaction)) | 	db.RegisterModel(new(Reaction)) | ||||||
| } | } | ||||||
| @@ -71,24 +133,25 @@ func (opts *FindReactionsOptions) toConds() builder.Cond { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // FindCommentReactions returns a ReactionList of all reactions from an comment | // FindCommentReactions returns a ReactionList of all reactions from an comment | ||||||
| func FindCommentReactions(comment *Comment) (ReactionList, int64, error) { | func FindCommentReactions(issueID, commentID int64) (ReactionList, int64, error) { | ||||||
| 	return findReactions(db.GetEngine(db.DefaultContext), FindReactionsOptions{ | 	return FindReactions(db.DefaultContext, FindReactionsOptions{ | ||||||
| 		IssueID:   comment.IssueID, | 		IssueID:   issueID, | ||||||
| 		CommentID: comment.ID, | 		CommentID: commentID, | ||||||
| 	}) | 	}) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // FindIssueReactions returns a ReactionList of all reactions from an issue | // FindIssueReactions returns a ReactionList of all reactions from an issue | ||||||
| func FindIssueReactions(issue *Issue, listOptions db.ListOptions) (ReactionList, int64, error) { | func FindIssueReactions(issueID int64, listOptions db.ListOptions) (ReactionList, int64, error) { | ||||||
| 	return findReactions(db.GetEngine(db.DefaultContext), FindReactionsOptions{ | 	return FindReactions(db.DefaultContext, FindReactionsOptions{ | ||||||
| 		ListOptions: listOptions, | 		ListOptions: listOptions, | ||||||
| 		IssueID:     issue.ID, | 		IssueID:     issueID, | ||||||
| 		CommentID:   -1, | 		CommentID:   -1, | ||||||
| 	}) | 	}) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func findReactions(e db.Engine, opts FindReactionsOptions) ([]*Reaction, int64, error) { | // FindReactions returns a ReactionList of all reactions from an issue or a comment | ||||||
| 	sess := e. | func FindReactions(ctx context.Context, opts FindReactionsOptions) (ReactionList, int64, error) { | ||||||
|  | 	sess := db.GetEngine(ctx). | ||||||
| 		Where(opts.toConds()). | 		Where(opts.toConds()). | ||||||
| 		In("reaction.`type`", setting.UI.Reactions). | 		In("reaction.`type`", setting.UI.Reactions). | ||||||
| 		Asc("reaction.issue_id", "reaction.comment_id", "reaction.created_unix", "reaction.id") | 		Asc("reaction.issue_id", "reaction.comment_id", "reaction.created_unix", "reaction.id") | ||||||
| @@ -105,24 +168,21 @@ func findReactions(e db.Engine, opts FindReactionsOptions) ([]*Reaction, int64, | |||||||
| 	return reactions, count, err | 	return reactions, count, err | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func createReaction(e db.Engine, opts *ReactionOptions) (*Reaction, error) { | func createReaction(ctx context.Context, opts *ReactionOptions) (*Reaction, error) { | ||||||
| 	reaction := &Reaction{ | 	reaction := &Reaction{ | ||||||
| 		Type:    opts.Type, | 		Type:      opts.Type, | ||||||
| 		UserID:  opts.Doer.ID, | 		UserID:    opts.DoerID, | ||||||
| 		IssueID: opts.Issue.ID, | 		IssueID:   opts.IssueID, | ||||||
|  | 		CommentID: opts.CommentID, | ||||||
| 	} | 	} | ||||||
| 	findOpts := FindReactionsOptions{ | 	findOpts := FindReactionsOptions{ | ||||||
| 		IssueID:   opts.Issue.ID, | 		IssueID:   opts.IssueID, | ||||||
| 		CommentID: -1, // reaction to issue only | 		CommentID: opts.CommentID, | ||||||
| 		Reaction:  opts.Type, | 		Reaction:  opts.Type, | ||||||
| 		UserID:    opts.Doer.ID, | 		UserID:    opts.DoerID, | ||||||
| 	} |  | ||||||
| 	if opts.Comment != nil { |  | ||||||
| 		reaction.CommentID = opts.Comment.ID |  | ||||||
| 		findOpts.CommentID = opts.Comment.ID |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	existingR, _, err := findReactions(e, findOpts) | 	existingR, _, err := FindReactions(ctx, findOpts) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, err | 		return nil, err | ||||||
| 	} | 	} | ||||||
| @@ -130,7 +190,7 @@ func createReaction(e db.Engine, opts *ReactionOptions) (*Reaction, error) { | |||||||
| 		return existingR[0], ErrReactionAlreadyExist{Reaction: opts.Type} | 		return existingR[0], ErrReactionAlreadyExist{Reaction: opts.Type} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if _, err := e.Insert(reaction); err != nil { | 	if err := db.Insert(ctx, reaction); err != nil { | ||||||
| 		return nil, err | 		return nil, err | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| @@ -139,10 +199,10 @@ func createReaction(e db.Engine, opts *ReactionOptions) (*Reaction, error) { | |||||||
| 
 | 
 | ||||||
| // ReactionOptions defines options for creating or deleting reactions | // ReactionOptions defines options for creating or deleting reactions | ||||||
| type ReactionOptions struct { | type ReactionOptions struct { | ||||||
| 	Type    string | 	Type      string | ||||||
| 	Doer    *user_model.User | 	DoerID    int64 | ||||||
| 	Issue   *Issue | 	IssueID   int64 | ||||||
| 	Comment *Comment | 	CommentID int64 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // CreateReaction creates reaction for issue or comment. | // CreateReaction creates reaction for issue or comment. | ||||||
| @@ -157,7 +217,7 @@ func CreateReaction(opts *ReactionOptions) (*Reaction, error) { | |||||||
| 	} | 	} | ||||||
| 	defer committer.Close() | 	defer committer.Close() | ||||||
| 
 | 
 | ||||||
| 	reaction, err := createReaction(db.GetEngine(ctx), opts) | 	reaction, err := createReaction(ctx, opts) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return reaction, err | 		return reaction, err | ||||||
| 	} | 	} | ||||||
| @@ -169,88 +229,56 @@ func CreateReaction(opts *ReactionOptions) (*Reaction, error) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // CreateIssueReaction creates a reaction on issue. | // CreateIssueReaction creates a reaction on issue. | ||||||
| func CreateIssueReaction(doer *user_model.User, issue *Issue, content string) (*Reaction, error) { | func CreateIssueReaction(doerID, issueID int64, content string) (*Reaction, error) { | ||||||
| 	return CreateReaction(&ReactionOptions{ | 	return CreateReaction(&ReactionOptions{ | ||||||
| 		Type:  content, | 		Type:    content, | ||||||
| 		Doer:  doer, | 		DoerID:  doerID, | ||||||
| 		Issue: issue, | 		IssueID: issueID, | ||||||
| 	}) | 	}) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // CreateCommentReaction creates a reaction on comment. | // CreateCommentReaction creates a reaction on comment. | ||||||
| func CreateCommentReaction(doer *user_model.User, issue *Issue, comment *Comment, content string) (*Reaction, error) { | func CreateCommentReaction(doerID, issueID, commentID int64, content string) (*Reaction, error) { | ||||||
| 	return CreateReaction(&ReactionOptions{ | 	return CreateReaction(&ReactionOptions{ | ||||||
| 		Type:    content, | 		Type:      content, | ||||||
| 		Doer:    doer, | 		DoerID:    doerID, | ||||||
| 		Issue:   issue, | 		IssueID:   issueID, | ||||||
| 		Comment: comment, | 		CommentID: commentID, | ||||||
| 	}) | 	}) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func deleteReaction(e db.Engine, opts *ReactionOptions) error { | // DeleteReaction deletes reaction for issue or comment. | ||||||
|  | func DeleteReaction(ctx context.Context, opts *ReactionOptions) error { | ||||||
| 	reaction := &Reaction{ | 	reaction := &Reaction{ | ||||||
| 		Type: opts.Type, | 		Type:      opts.Type, | ||||||
|  | 		UserID:    opts.DoerID, | ||||||
|  | 		IssueID:   opts.IssueID, | ||||||
|  | 		CommentID: opts.CommentID, | ||||||
| 	} | 	} | ||||||
| 	if opts.Doer != nil { | 
 | ||||||
| 		reaction.UserID = opts.Doer.ID | 	_, err := db.GetEngine(ctx).Where("original_author_id = 0").Delete(reaction) | ||||||
| 	} |  | ||||||
| 	if opts.Issue != nil { |  | ||||||
| 		reaction.IssueID = opts.Issue.ID |  | ||||||
| 	} |  | ||||||
| 	if opts.Comment != nil { |  | ||||||
| 		reaction.CommentID = opts.Comment.ID |  | ||||||
| 	} |  | ||||||
| 	_, err := e.Where("original_author_id = 0").Delete(reaction) |  | ||||||
| 	return err | 	return err | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // DeleteReaction deletes reaction for issue or comment. |  | ||||||
| func DeleteReaction(opts *ReactionOptions) error { |  | ||||||
| 	ctx, committer, err := db.TxContext() |  | ||||||
| 	if err != nil { |  | ||||||
| 		return err |  | ||||||
| 	} |  | ||||||
| 	defer committer.Close() |  | ||||||
| 
 |  | ||||||
| 	if err := deleteReaction(db.GetEngine(ctx), opts); err != nil { |  | ||||||
| 		return err |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	return committer.Commit() |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // DeleteIssueReaction deletes a reaction on issue. | // DeleteIssueReaction deletes a reaction on issue. | ||||||
| func DeleteIssueReaction(doer *user_model.User, issue *Issue, content string) error { | func DeleteIssueReaction(doerID, issueID int64, content string) error { | ||||||
| 	return DeleteReaction(&ReactionOptions{ | 	return DeleteReaction(db.DefaultContext, &ReactionOptions{ | ||||||
| 		Type:  content, | 		Type:    content, | ||||||
| 		Doer:  doer, | 		DoerID:  doerID, | ||||||
| 		Issue: issue, | 		IssueID: issueID, | ||||||
| 	}) | 	}) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // DeleteCommentReaction deletes a reaction on comment. | // DeleteCommentReaction deletes a reaction on comment. | ||||||
| func DeleteCommentReaction(doer *user_model.User, issue *Issue, comment *Comment, content string) error { | func DeleteCommentReaction(doerID, issueID, commentID int64, content string) error { | ||||||
| 	return DeleteReaction(&ReactionOptions{ | 	return DeleteReaction(db.DefaultContext, &ReactionOptions{ | ||||||
| 		Type:    content, | 		Type:      content, | ||||||
| 		Doer:    doer, | 		DoerID:    doerID, | ||||||
| 		Issue:   issue, | 		IssueID:   issueID, | ||||||
| 		Comment: comment, | 		CommentID: commentID, | ||||||
| 	}) | 	}) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // LoadUser load user of reaction |  | ||||||
| func (r *Reaction) LoadUser() (*user_model.User, error) { |  | ||||||
| 	if r.User != nil { |  | ||||||
| 		return r.User, nil |  | ||||||
| 	} |  | ||||||
| 	user, err := user_model.GetUserByIDCtx(db.DefaultContext, r.UserID) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	r.User = user |  | ||||||
| 	return user, nil |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // ReactionList represents list of reactions | // ReactionList represents list of reactions | ||||||
| type ReactionList []*Reaction | type ReactionList []*Reaction | ||||||
| 
 | 
 | ||||||
| @@ -286,17 +314,26 @@ func (list ReactionList) getUserIDs() []int64 { | |||||||
| 			userIDs[reaction.UserID] = struct{}{} | 			userIDs[reaction.UserID] = struct{}{} | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	return keysInt64(userIDs) | 	return container.KeysInt64(userIDs) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (list ReactionList) loadUsers(e db.Engine, repo *repo_model.Repository) ([]*user_model.User, error) { | func valuesUser(m map[int64]*user_model.User) []*user_model.User { | ||||||
|  | 	values := make([]*user_model.User, 0, len(m)) | ||||||
|  | 	for _, v := range m { | ||||||
|  | 		values = append(values, v) | ||||||
|  | 	} | ||||||
|  | 	return values | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // LoadUsers loads reactions' all users | ||||||
|  | func (list ReactionList) LoadUsers(ctx context.Context, repo *repo_model.Repository) ([]*user_model.User, error) { | ||||||
| 	if len(list) == 0 { | 	if len(list) == 0 { | ||||||
| 		return nil, nil | 		return nil, nil | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	userIDs := list.getUserIDs() | 	userIDs := list.getUserIDs() | ||||||
| 	userMaps := make(map[int64]*user_model.User, len(userIDs)) | 	userMaps := make(map[int64]*user_model.User, len(userIDs)) | ||||||
| 	err := e. | 	err := db.GetEngine(ctx). | ||||||
| 		In("id", userIDs). | 		In("id", userIDs). | ||||||
| 		Find(&userMaps) | 		Find(&userMaps) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| @@ -315,11 +352,6 @@ func (list ReactionList) loadUsers(e db.Engine, repo *repo_model.Repository) ([] | |||||||
| 	return valuesUser(userMaps), nil | 	return valuesUser(userMaps), nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // LoadUsers loads reactions' all users |  | ||||||
| func (list ReactionList) LoadUsers(repo *repo_model.Repository) ([]*user_model.User, error) { |  | ||||||
| 	return list.loadUsers(db.GetEngine(db.DefaultContext), repo) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // GetFirstUsers returns first reacted user display names separated by comma | // GetFirstUsers returns first reacted user display names separated by comma | ||||||
| func (list ReactionList) GetFirstUsers() string { | func (list ReactionList) GetFirstUsers() string { | ||||||
| 	var buffer bytes.Buffer | 	var buffer bytes.Buffer | ||||||
| @@ -343,20 +375,3 @@ func (list ReactionList) GetMoreUserCount() int { | |||||||
| 	} | 	} | ||||||
| 	return len(list) - setting.UI.ReactionMaxUserNum | 	return len(list) - setting.UI.ReactionMaxUserNum | ||||||
| } | } | ||||||
| 
 |  | ||||||
| // RemapExternalUser ExternalUserRemappable interface |  | ||||||
| func (r *Reaction) RemapExternalUser(externalName string, externalID, userID int64) error { |  | ||||||
| 	r.OriginalAuthor = externalName |  | ||||||
| 	r.OriginalAuthorID = externalID |  | ||||||
| 	r.UserID = userID |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // GetUserID ExternalUserRemappable interface |  | ||||||
| func (r *Reaction) GetUserID() int64 { return r.UserID } |  | ||||||
| 
 |  | ||||||
| // GetExternalName ExternalUserRemappable interface |  | ||||||
| func (r *Reaction) GetExternalName() string { return r.OriginalAuthor } |  | ||||||
| 
 |  | ||||||
| // GetExternalID ExternalUserRemappable interface |  | ||||||
| func (r *Reaction) GetExternalID() int64 { return r.OriginalAuthorID } |  | ||||||
| @@ -1,7 +1,8 @@ | |||||||
| // Copyright 2017 The Gitea Authors. All rights reserved. | // Copyright 2017 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 models | 
 | ||||||
|  | package issues | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"testing" | 	"testing" | ||||||
| @@ -15,13 +16,13 @@ import ( | |||||||
| 	"github.com/stretchr/testify/assert" | 	"github.com/stretchr/testify/assert" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| func addReaction(t *testing.T, doer *user_model.User, issue *Issue, comment *Comment, content string) { | func addReaction(t *testing.T, doerID, issueID, commentID int64, content string) { | ||||||
| 	var reaction *Reaction | 	var reaction *Reaction | ||||||
| 	var err error | 	var err error | ||||||
| 	if comment == nil { | 	if commentID == 0 { | ||||||
| 		reaction, err = CreateIssueReaction(doer, issue, content) | 		reaction, err = CreateIssueReaction(doerID, issueID, content) | ||||||
| 	} else { | 	} else { | ||||||
| 		reaction, err = CreateCommentReaction(doer, issue, comment, content) | 		reaction, err = CreateCommentReaction(doerID, issueID, commentID, content) | ||||||
| 	} | 	} | ||||||
| 	assert.NoError(t, err) | 	assert.NoError(t, err) | ||||||
| 	assert.NotNil(t, reaction) | 	assert.NotNil(t, reaction) | ||||||
| @@ -32,11 +33,11 @@ func TestIssueAddReaction(t *testing.T) { | |||||||
| 
 | 
 | ||||||
| 	user1 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}).(*user_model.User) | 	user1 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}).(*user_model.User) | ||||||
| 
 | 
 | ||||||
| 	issue1 := unittest.AssertExistsAndLoadBean(t, &Issue{ID: 1}).(*Issue) | 	var issue1ID int64 = 1 | ||||||
| 
 | 
 | ||||||
| 	addReaction(t, user1, issue1, nil, "heart") | 	addReaction(t, user1.ID, issue1ID, 0, "heart") | ||||||
| 
 | 
 | ||||||
| 	unittest.AssertExistsAndLoadBean(t, &Reaction{Type: "heart", UserID: user1.ID, IssueID: issue1.ID}) | 	unittest.AssertExistsAndLoadBean(t, &Reaction{Type: "heart", UserID: user1.ID, IssueID: issue1ID}) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func TestIssueAddDuplicateReaction(t *testing.T) { | func TestIssueAddDuplicateReaction(t *testing.T) { | ||||||
| @@ -44,19 +45,19 @@ func TestIssueAddDuplicateReaction(t *testing.T) { | |||||||
| 
 | 
 | ||||||
| 	user1 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}).(*user_model.User) | 	user1 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}).(*user_model.User) | ||||||
| 
 | 
 | ||||||
| 	issue1 := unittest.AssertExistsAndLoadBean(t, &Issue{ID: 1}).(*Issue) | 	var issue1ID int64 = 1 | ||||||
| 
 | 
 | ||||||
| 	addReaction(t, user1, issue1, nil, "heart") | 	addReaction(t, user1.ID, issue1ID, 0, "heart") | ||||||
| 
 | 
 | ||||||
| 	reaction, err := CreateReaction(&ReactionOptions{ | 	reaction, err := CreateReaction(&ReactionOptions{ | ||||||
| 		Doer:  user1, | 		DoerID:  user1.ID, | ||||||
| 		Issue: issue1, | 		IssueID: issue1ID, | ||||||
| 		Type:  "heart", | 		Type:    "heart", | ||||||
| 	}) | 	}) | ||||||
| 	assert.Error(t, err) | 	assert.Error(t, err) | ||||||
| 	assert.Equal(t, ErrReactionAlreadyExist{Reaction: "heart"}, err) | 	assert.Equal(t, ErrReactionAlreadyExist{Reaction: "heart"}, err) | ||||||
| 
 | 
 | ||||||
| 	existingR := unittest.AssertExistsAndLoadBean(t, &Reaction{Type: "heart", UserID: user1.ID, IssueID: issue1.ID}).(*Reaction) | 	existingR := unittest.AssertExistsAndLoadBean(t, &Reaction{Type: "heart", UserID: user1.ID, IssueID: issue1ID}).(*Reaction) | ||||||
| 	assert.Equal(t, existingR.ID, reaction.ID) | 	assert.Equal(t, existingR.ID, reaction.ID) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @@ -65,14 +66,14 @@ func TestIssueDeleteReaction(t *testing.T) { | |||||||
| 
 | 
 | ||||||
| 	user1 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}).(*user_model.User) | 	user1 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}).(*user_model.User) | ||||||
| 
 | 
 | ||||||
| 	issue1 := unittest.AssertExistsAndLoadBean(t, &Issue{ID: 1}).(*Issue) | 	var issue1ID int64 = 1 | ||||||
| 
 | 
 | ||||||
| 	addReaction(t, user1, issue1, nil, "heart") | 	addReaction(t, user1.ID, issue1ID, 0, "heart") | ||||||
| 
 | 
 | ||||||
| 	err := DeleteIssueReaction(user1, issue1, "heart") | 	err := DeleteIssueReaction(user1.ID, issue1ID, "heart") | ||||||
| 	assert.NoError(t, err) | 	assert.NoError(t, err) | ||||||
| 
 | 
 | ||||||
| 	unittest.AssertNotExistsBean(t, &Reaction{Type: "heart", UserID: user1.ID, IssueID: issue1.ID}) | 	unittest.AssertNotExistsBean(t, &Reaction{Type: "heart", UserID: user1.ID, IssueID: issue1ID}) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func TestIssueReactionCount(t *testing.T) { | func TestIssueReactionCount(t *testing.T) { | ||||||
| @@ -86,22 +87,26 @@ func TestIssueReactionCount(t *testing.T) { | |||||||
| 	user4 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}).(*user_model.User) | 	user4 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}).(*user_model.User) | ||||||
| 	ghost := user_model.NewGhostUser() | 	ghost := user_model.NewGhostUser() | ||||||
| 
 | 
 | ||||||
| 	issue := unittest.AssertExistsAndLoadBean(t, &Issue{ID: 2}).(*Issue) | 	var issueID int64 = 2 | ||||||
|  | 	repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) | ||||||
| 
 | 
 | ||||||
| 	addReaction(t, user1, issue, nil, "heart") | 	addReaction(t, user1.ID, issueID, 0, "heart") | ||||||
| 	addReaction(t, user2, issue, nil, "heart") | 	addReaction(t, user2.ID, issueID, 0, "heart") | ||||||
| 	addReaction(t, user3, issue, nil, "heart") | 	addReaction(t, user3.ID, issueID, 0, "heart") | ||||||
| 	addReaction(t, user3, issue, nil, "+1") | 	addReaction(t, user3.ID, issueID, 0, "+1") | ||||||
| 	addReaction(t, user4, issue, nil, "+1") | 	addReaction(t, user4.ID, issueID, 0, "+1") | ||||||
| 	addReaction(t, user4, issue, nil, "heart") | 	addReaction(t, user4.ID, issueID, 0, "heart") | ||||||
| 	addReaction(t, ghost, issue, nil, "-1") | 	addReaction(t, ghost.ID, issueID, 0, "-1") | ||||||
| 
 | 
 | ||||||
| 	err := issue.loadReactions(db.DefaultContext) | 	reactionsList, _, err := FindReactions(db.DefaultContext, FindReactionsOptions{ | ||||||
|  | 		IssueID: issueID, | ||||||
|  | 	}) | ||||||
|  | 	assert.NoError(t, err) | ||||||
|  | 	assert.Len(t, reactionsList, 7) | ||||||
|  | 	_, err = reactionsList.LoadUsers(db.DefaultContext, repo) | ||||||
| 	assert.NoError(t, err) | 	assert.NoError(t, err) | ||||||
| 
 | 
 | ||||||
| 	assert.Len(t, issue.Reactions, 7) | 	reactions := reactionsList.GroupByType() | ||||||
| 
 |  | ||||||
| 	reactions := issue.Reactions.GroupByType() |  | ||||||
| 	assert.Len(t, reactions["heart"], 4) | 	assert.Len(t, reactions["heart"], 4) | ||||||
| 	assert.Equal(t, 2, reactions["heart"].GetMoreUserCount()) | 	assert.Equal(t, 2, reactions["heart"].GetMoreUserCount()) | ||||||
| 	assert.Equal(t, user1.DisplayName()+", "+user2.DisplayName(), reactions["heart"].GetFirstUsers()) | 	assert.Equal(t, user1.DisplayName()+", "+user2.DisplayName(), reactions["heart"].GetFirstUsers()) | ||||||
| @@ -118,13 +123,12 @@ func TestIssueCommentAddReaction(t *testing.T) { | |||||||
| 
 | 
 | ||||||
| 	user1 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}).(*user_model.User) | 	user1 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}).(*user_model.User) | ||||||
| 
 | 
 | ||||||
| 	issue1 := unittest.AssertExistsAndLoadBean(t, &Issue{ID: 1}).(*Issue) | 	var issue1ID int64 = 1 | ||||||
|  | 	var comment1ID int64 = 1 | ||||||
| 
 | 
 | ||||||
| 	comment1 := unittest.AssertExistsAndLoadBean(t, &Comment{ID: 1}).(*Comment) | 	addReaction(t, user1.ID, issue1ID, comment1ID, "heart") | ||||||
| 
 | 
 | ||||||
| 	addReaction(t, user1, issue1, comment1, "heart") | 	unittest.AssertExistsAndLoadBean(t, &Reaction{Type: "heart", UserID: user1.ID, IssueID: issue1ID, CommentID: comment1ID}) | ||||||
| 
 |  | ||||||
| 	unittest.AssertExistsAndLoadBean(t, &Reaction{Type: "heart", UserID: user1.ID, IssueID: issue1.ID, CommentID: comment1.ID}) |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func TestIssueCommentDeleteReaction(t *testing.T) { | func TestIssueCommentDeleteReaction(t *testing.T) { | ||||||
| @@ -135,21 +139,22 @@ func TestIssueCommentDeleteReaction(t *testing.T) { | |||||||
| 	user3 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3}).(*user_model.User) | 	user3 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3}).(*user_model.User) | ||||||
| 	user4 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}).(*user_model.User) | 	user4 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}).(*user_model.User) | ||||||
| 
 | 
 | ||||||
| 	issue1 := unittest.AssertExistsAndLoadBean(t, &Issue{ID: 1}).(*Issue) | 	var issue1ID int64 = 1 | ||||||
| 	repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issue1.RepoID}).(*repo_model.Repository) | 	var comment1ID int64 = 1 | ||||||
| 
 | 
 | ||||||
| 	comment1 := unittest.AssertExistsAndLoadBean(t, &Comment{ID: 1}).(*Comment) | 	addReaction(t, user1.ID, issue1ID, comment1ID, "heart") | ||||||
|  | 	addReaction(t, user2.ID, issue1ID, comment1ID, "heart") | ||||||
|  | 	addReaction(t, user3.ID, issue1ID, comment1ID, "heart") | ||||||
|  | 	addReaction(t, user4.ID, issue1ID, comment1ID, "+1") | ||||||
| 
 | 
 | ||||||
| 	addReaction(t, user1, issue1, comment1, "heart") | 	reactionsList, _, err := FindReactions(db.DefaultContext, FindReactionsOptions{ | ||||||
| 	addReaction(t, user2, issue1, comment1, "heart") | 		IssueID:   issue1ID, | ||||||
| 	addReaction(t, user3, issue1, comment1, "heart") | 		CommentID: comment1ID, | ||||||
| 	addReaction(t, user4, issue1, comment1, "+1") | 	}) | ||||||
| 
 |  | ||||||
| 	err := comment1.LoadReactions(repo1) |  | ||||||
| 	assert.NoError(t, err) | 	assert.NoError(t, err) | ||||||
| 	assert.Len(t, comment1.Reactions, 4) | 	assert.Len(t, reactionsList, 4) | ||||||
| 
 | 
 | ||||||
| 	reactions := comment1.Reactions.GroupByType() | 	reactions := reactionsList.GroupByType() | ||||||
| 	assert.Len(t, reactions["heart"], 3) | 	assert.Len(t, reactions["heart"], 3) | ||||||
| 	assert.Len(t, reactions["+1"], 1) | 	assert.Len(t, reactions["+1"], 1) | ||||||
| } | } | ||||||
| @@ -159,12 +164,11 @@ func TestIssueCommentReactionCount(t *testing.T) { | |||||||
| 
 | 
 | ||||||
| 	user1 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}).(*user_model.User) | 	user1 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}).(*user_model.User) | ||||||
| 
 | 
 | ||||||
| 	issue1 := unittest.AssertExistsAndLoadBean(t, &Issue{ID: 1}).(*Issue) | 	var issue1ID int64 = 1 | ||||||
|  | 	var comment1ID int64 = 1 | ||||||
| 
 | 
 | ||||||
| 	comment1 := unittest.AssertExistsAndLoadBean(t, &Comment{ID: 1}).(*Comment) | 	addReaction(t, user1.ID, issue1ID, comment1ID, "heart") | ||||||
|  | 	assert.NoError(t, DeleteCommentReaction(user1.ID, issue1ID, comment1ID, "heart")) | ||||||
| 
 | 
 | ||||||
| 	addReaction(t, user1, issue1, comment1, "heart") | 	unittest.AssertNotExistsBean(t, &Reaction{Type: "heart", UserID: user1.ID, IssueID: issue1ID, CommentID: comment1ID}) | ||||||
| 	assert.NoError(t, DeleteCommentReaction(user1, issue1, comment1, "heart")) |  | ||||||
| 
 |  | ||||||
| 	unittest.AssertNotExistsBean(t, &Reaction{Type: "heart", UserID: user1.ID, IssueID: issue1.ID, CommentID: comment1.ID}) |  | ||||||
| } | } | ||||||
| @@ -9,6 +9,7 @@ import ( | |||||||
| 	"testing" | 	"testing" | ||||||
|  |  | ||||||
| 	"code.gitea.io/gitea/models/foreignreference" | 	"code.gitea.io/gitea/models/foreignreference" | ||||||
|  | 	issues_model "code.gitea.io/gitea/models/issues" | ||||||
| 	repo_model "code.gitea.io/gitea/models/repo" | 	repo_model "code.gitea.io/gitea/models/repo" | ||||||
| 	"code.gitea.io/gitea/models/unittest" | 	"code.gitea.io/gitea/models/unittest" | ||||||
| 	user_model "code.gitea.io/gitea/models/user" | 	user_model "code.gitea.io/gitea/models/user" | ||||||
| @@ -42,7 +43,7 @@ func assertCreateIssues(t *testing.T, isPull bool) { | |||||||
| 	label := unittest.AssertExistsAndLoadBean(t, &Label{ID: 1}).(*Label) | 	label := unittest.AssertExistsAndLoadBean(t, &Label{ID: 1}).(*Label) | ||||||
| 	milestone := unittest.AssertExistsAndLoadBean(t, &Milestone{ID: 1}).(*Milestone) | 	milestone := unittest.AssertExistsAndLoadBean(t, &Milestone{ID: 1}).(*Milestone) | ||||||
| 	assert.EqualValues(t, milestone.ID, 1) | 	assert.EqualValues(t, milestone.ID, 1) | ||||||
| 	reaction := &Reaction{ | 	reaction := &issues_model.Reaction{ | ||||||
| 		Type:   "heart", | 		Type:   "heart", | ||||||
| 		UserID: owner.ID, | 		UserID: owner.ID, | ||||||
| 	} | 	} | ||||||
| @@ -60,7 +61,7 @@ func assertCreateIssues(t *testing.T, isPull bool) { | |||||||
| 		Poster:      owner, | 		Poster:      owner, | ||||||
| 		IsClosed:    true, | 		IsClosed:    true, | ||||||
| 		Labels:      []*Label{label}, | 		Labels:      []*Label{label}, | ||||||
| 		Reactions:   []*Reaction{reaction}, | 		Reactions:   []*issues_model.Reaction{reaction}, | ||||||
| 		ForeignReference: &foreignreference.ForeignReference{ | 		ForeignReference: &foreignreference.ForeignReference{ | ||||||
| 			ForeignIndex: strconv.FormatInt(foreignIndex, 10), | 			ForeignIndex: strconv.FormatInt(foreignIndex, 10), | ||||||
| 			RepoID:       repo.ID, | 			RepoID:       repo.ID, | ||||||
| @@ -75,7 +76,7 @@ func assertCreateIssues(t *testing.T, isPull bool) { | |||||||
| 	err = i.LoadAttributes() | 	err = i.LoadAttributes() | ||||||
| 	assert.NoError(t, err) | 	assert.NoError(t, err) | ||||||
| 	assert.EqualValues(t, strconv.FormatInt(foreignIndex, 10), i.ForeignReference.ForeignIndex) | 	assert.EqualValues(t, strconv.FormatInt(foreignIndex, 10), i.ForeignReference.ForeignIndex) | ||||||
| 	unittest.AssertExistsAndLoadBean(t, &Reaction{Type: "heart", UserID: owner.ID, IssueID: i.ID}) | 	unittest.AssertExistsAndLoadBean(t, &issues_model.Reaction{Type: "heart", UserID: owner.ID, IssueID: i.ID}) | ||||||
| } | } | ||||||
|  |  | ||||||
| func TestMigrate_CreateIssuesIsPullFalse(t *testing.T) { | func TestMigrate_CreateIssuesIsPullFalse(t *testing.T) { | ||||||
| @@ -91,7 +92,7 @@ func TestMigrate_InsertIssueComments(t *testing.T) { | |||||||
| 	issue := unittest.AssertExistsAndLoadBean(t, &Issue{ID: 1}).(*Issue) | 	issue := unittest.AssertExistsAndLoadBean(t, &Issue{ID: 1}).(*Issue) | ||||||
| 	_ = issue.LoadRepo() | 	_ = issue.LoadRepo() | ||||||
| 	owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: issue.Repo.OwnerID}).(*user_model.User) | 	owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: issue.Repo.OwnerID}).(*user_model.User) | ||||||
| 	reaction := &Reaction{ | 	reaction := &issues_model.Reaction{ | ||||||
| 		Type:   "heart", | 		Type:   "heart", | ||||||
| 		UserID: owner.ID, | 		UserID: owner.ID, | ||||||
| 	} | 	} | ||||||
| @@ -101,7 +102,7 @@ func TestMigrate_InsertIssueComments(t *testing.T) { | |||||||
| 		Poster:    owner, | 		Poster:    owner, | ||||||
| 		IssueID:   issue.ID, | 		IssueID:   issue.ID, | ||||||
| 		Issue:     issue, | 		Issue:     issue, | ||||||
| 		Reactions: []*Reaction{reaction}, | 		Reactions: []*issues_model.Reaction{reaction}, | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	err := InsertIssueComments([]*Comment{comment}) | 	err := InsertIssueComments([]*Comment{comment}) | ||||||
|   | |||||||
| @@ -15,6 +15,7 @@ import ( | |||||||
| 	repo_model "code.gitea.io/gitea/models/repo" | 	repo_model "code.gitea.io/gitea/models/repo" | ||||||
| 	"code.gitea.io/gitea/models/unit" | 	"code.gitea.io/gitea/models/unit" | ||||||
| 	user_model "code.gitea.io/gitea/models/user" | 	user_model "code.gitea.io/gitea/models/user" | ||||||
|  | 	"code.gitea.io/gitea/modules/container" | ||||||
| 	"code.gitea.io/gitea/modules/log" | 	"code.gitea.io/gitea/modules/log" | ||||||
| 	"code.gitea.io/gitea/modules/setting" | 	"code.gitea.io/gitea/modules/setting" | ||||||
| 	"code.gitea.io/gitea/modules/timeutil" | 	"code.gitea.io/gitea/modules/timeutil" | ||||||
| @@ -520,7 +521,7 @@ func (nl NotificationList) getPendingRepoIDs() []int64 { | |||||||
| 			ids[notification.RepoID] = struct{}{} | 			ids[notification.RepoID] = struct{}{} | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	return keysInt64(ids) | 	return container.KeysInt64(ids) | ||||||
| } | } | ||||||
|  |  | ||||||
| // LoadRepos loads repositories from database | // LoadRepos loads repositories from database | ||||||
| @@ -596,7 +597,7 @@ func (nl NotificationList) getPendingIssueIDs() []int64 { | |||||||
| 			ids[notification.IssueID] = struct{}{} | 			ids[notification.IssueID] = struct{}{} | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	return keysInt64(ids) | 	return container.KeysInt64(ids) | ||||||
| } | } | ||||||
|  |  | ||||||
| // LoadIssues loads issues from database | // LoadIssues loads issues from database | ||||||
| @@ -682,7 +683,7 @@ func (nl NotificationList) getPendingCommentIDs() []int64 { | |||||||
| 			ids[notification.CommentID] = struct{}{} | 			ids[notification.CommentID] = struct{}{} | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	return keysInt64(ids) | 	return container.KeysInt64(ids) | ||||||
| } | } | ||||||
|  |  | ||||||
| // LoadComments loads comments from database | // LoadComments loads comments from database | ||||||
|   | |||||||
| @@ -13,6 +13,7 @@ import ( | |||||||
| 	repo_model "code.gitea.io/gitea/models/repo" | 	repo_model "code.gitea.io/gitea/models/repo" | ||||||
| 	"code.gitea.io/gitea/models/unit" | 	"code.gitea.io/gitea/models/unit" | ||||||
| 	user_model "code.gitea.io/gitea/models/user" | 	user_model "code.gitea.io/gitea/models/user" | ||||||
|  | 	"code.gitea.io/gitea/modules/container" | ||||||
| 	"code.gitea.io/gitea/modules/structs" | 	"code.gitea.io/gitea/modules/structs" | ||||||
| 	"code.gitea.io/gitea/modules/util" | 	"code.gitea.io/gitea/modules/util" | ||||||
|  |  | ||||||
| @@ -62,7 +63,7 @@ func (repos RepositoryList) loadAttributes(e db.Engine) error { | |||||||
| 	users := make(map[int64]*user_model.User, len(set)) | 	users := make(map[int64]*user_model.User, len(set)) | ||||||
| 	if err := e. | 	if err := e. | ||||||
| 		Where("id > 0"). | 		Where("id > 0"). | ||||||
| 		In("id", keysInt64(set)). | 		In("id", container.KeysInt64(set)). | ||||||
| 		Find(&users); err != nil { | 		Find(&users); err != nil { | ||||||
| 		return fmt.Errorf("find users: %v", err) | 		return fmt.Errorf("find users: %v", err) | ||||||
| 	} | 	} | ||||||
|   | |||||||
| @@ -14,6 +14,7 @@ import ( | |||||||
|  |  | ||||||
| 	asymkey_model "code.gitea.io/gitea/models/asymkey" | 	asymkey_model "code.gitea.io/gitea/models/asymkey" | ||||||
| 	"code.gitea.io/gitea/models/db" | 	"code.gitea.io/gitea/models/db" | ||||||
|  | 	"code.gitea.io/gitea/models/issues" | ||||||
| 	"code.gitea.io/gitea/models/organization" | 	"code.gitea.io/gitea/models/organization" | ||||||
| 	repo_model "code.gitea.io/gitea/models/repo" | 	repo_model "code.gitea.io/gitea/models/repo" | ||||||
| 	user_model "code.gitea.io/gitea/models/user" | 	user_model "code.gitea.io/gitea/models/user" | ||||||
| @@ -76,7 +77,7 @@ func DeleteUser(ctx context.Context, u *user_model.User) (err error) { | |||||||
| 		&IssueUser{UID: u.ID}, | 		&IssueUser{UID: u.ID}, | ||||||
| 		&user_model.EmailAddress{UID: u.ID}, | 		&user_model.EmailAddress{UID: u.ID}, | ||||||
| 		&user_model.UserOpenID{UID: u.ID}, | 		&user_model.UserOpenID{UID: u.ID}, | ||||||
| 		&Reaction{UserID: u.ID}, | 		&issues.Reaction{UserID: u.ID}, | ||||||
| 		&organization.TeamUser{UID: u.ID}, | 		&organization.TeamUser{UID: u.ID}, | ||||||
| 		&Collaboration{UserID: u.ID}, | 		&Collaboration{UserID: u.ID}, | ||||||
| 		&Stopwatch{UserID: u.ID}, | 		&Stopwatch{UserID: u.ID}, | ||||||
| @@ -100,14 +101,14 @@ func DeleteUser(ctx context.Context, u *user_model.User) (err error) { | |||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			for _, comment := range comments { | 			for _, comment := range comments { | ||||||
| 				if err = deleteComment(e, comment); err != nil { | 				if err = deleteComment(ctx, comment); err != nil { | ||||||
| 					return err | 					return err | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		// Delete Reactions | 		// Delete Reactions | ||||||
| 		if err = deleteReaction(e, &ReactionOptions{Doer: u}); err != nil { | 		if err = issues.DeleteReaction(ctx, &issues.ReactionOptions{DoerID: u.ID}); err != nil { | ||||||
| 			return err | 			return err | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|   | |||||||
							
								
								
									
										14
									
								
								modules/container/map.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								modules/container/map.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | |||||||
|  | // Copyright 2022 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 container | ||||||
|  |  | ||||||
|  | // KeysInt64 returns keys slice for a map with int64 key | ||||||
|  | func KeysInt64(m map[int64]struct{}) []int64 { | ||||||
|  | 	keys := make([]int64, 0, len(m)) | ||||||
|  | 	for k := range m { | ||||||
|  | 		keys = append(keys, k) | ||||||
|  | 	} | ||||||
|  | 	return keys | ||||||
|  | } | ||||||
| @@ -9,6 +9,7 @@ import ( | |||||||
| 	"net/http" | 	"net/http" | ||||||
|  |  | ||||||
| 	"code.gitea.io/gitea/models" | 	"code.gitea.io/gitea/models" | ||||||
|  | 	issues_model "code.gitea.io/gitea/models/issues" | ||||||
| 	"code.gitea.io/gitea/modules/context" | 	"code.gitea.io/gitea/modules/context" | ||||||
| 	"code.gitea.io/gitea/modules/convert" | 	"code.gitea.io/gitea/modules/convert" | ||||||
| 	api "code.gitea.io/gitea/modules/structs" | 	api "code.gitea.io/gitea/modules/structs" | ||||||
| @@ -67,12 +68,12 @@ func GetIssueCommentReactions(ctx *context.APIContext) { | |||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	reactions, _, err := models.FindCommentReactions(comment) | 	reactions, _, err := issues_model.FindCommentReactions(comment.IssueID, comment.ID) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		ctx.Error(http.StatusInternalServerError, "FindCommentReactions", err) | 		ctx.Error(http.StatusInternalServerError, "FindCommentReactions", err) | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 	_, err = reactions.LoadUsers(ctx.Repo.Repository) | 	_, err = reactions.LoadUsers(ctx, 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 | ||||||
| @@ -197,11 +198,11 @@ func changeIssueCommentReaction(ctx *context.APIContext, form api.EditReactionOp | |||||||
|  |  | ||||||
| 	if isCreateType { | 	if isCreateType { | ||||||
| 		// PostIssueCommentReaction part | 		// PostIssueCommentReaction part | ||||||
| 		reaction, err := models.CreateCommentReaction(ctx.Doer, comment.Issue, comment, form.Reaction) | 		reaction, err := issues_model.CreateCommentReaction(ctx.Doer.ID, comment.Issue.ID, comment.ID, form.Reaction) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			if models.IsErrForbiddenIssueReaction(err) { | 			if issues_model.IsErrForbiddenIssueReaction(err) { | ||||||
| 				ctx.Error(http.StatusForbidden, err.Error(), err) | 				ctx.Error(http.StatusForbidden, err.Error(), err) | ||||||
| 			} else if models.IsErrReactionAlreadyExist(err) { | 			} else if issues_model.IsErrReactionAlreadyExist(err) { | ||||||
| 				ctx.JSON(http.StatusOK, api.Reaction{ | 				ctx.JSON(http.StatusOK, api.Reaction{ | ||||||
| 					User:     convert.ToUser(ctx.Doer, ctx.Doer), | 					User:     convert.ToUser(ctx.Doer, ctx.Doer), | ||||||
| 					Reaction: reaction.Type, | 					Reaction: reaction.Type, | ||||||
| @@ -220,7 +221,7 @@ func changeIssueCommentReaction(ctx *context.APIContext, form api.EditReactionOp | |||||||
| 		}) | 		}) | ||||||
| 	} else { | 	} else { | ||||||
| 		// DeleteIssueCommentReaction part | 		// DeleteIssueCommentReaction part | ||||||
| 		err = models.DeleteCommentReaction(ctx.Doer, comment.Issue, comment, form.Reaction) | 		err = issues_model.DeleteCommentReaction(ctx.Doer.ID, comment.Issue.ID, comment.ID, form.Reaction) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			ctx.Error(http.StatusInternalServerError, "DeleteCommentReaction", err) | 			ctx.Error(http.StatusInternalServerError, "DeleteCommentReaction", err) | ||||||
| 			return | 			return | ||||||
| @@ -285,12 +286,12 @@ func GetIssueReactions(ctx *context.APIContext) { | |||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	reactions, count, err := models.FindIssueReactions(issue, utils.GetListOptions(ctx)) | 	reactions, count, err := issues_model.FindIssueReactions(issue.ID, utils.GetListOptions(ctx)) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		ctx.Error(http.StatusInternalServerError, "FindIssueReactions", err) | 		ctx.Error(http.StatusInternalServerError, "FindIssueReactions", err) | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 	_, err = reactions.LoadUsers(ctx.Repo.Repository) | 	_, err = reactions.LoadUsers(ctx, 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 | ||||||
| @@ -407,11 +408,11 @@ func changeIssueReaction(ctx *context.APIContext, form api.EditReactionOption, i | |||||||
|  |  | ||||||
| 	if isCreateType { | 	if isCreateType { | ||||||
| 		// PostIssueReaction part | 		// PostIssueReaction part | ||||||
| 		reaction, err := models.CreateIssueReaction(ctx.Doer, issue, form.Reaction) | 		reaction, err := issues_model.CreateIssueReaction(ctx.Doer.ID, issue.ID, form.Reaction) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			if models.IsErrForbiddenIssueReaction(err) { | 			if issues_model.IsErrForbiddenIssueReaction(err) { | ||||||
| 				ctx.Error(http.StatusForbidden, err.Error(), err) | 				ctx.Error(http.StatusForbidden, err.Error(), err) | ||||||
| 			} else if models.IsErrReactionAlreadyExist(err) { | 			} else if issues_model.IsErrReactionAlreadyExist(err) { | ||||||
| 				ctx.JSON(http.StatusOK, api.Reaction{ | 				ctx.JSON(http.StatusOK, api.Reaction{ | ||||||
| 					User:     convert.ToUser(ctx.Doer, ctx.Doer), | 					User:     convert.ToUser(ctx.Doer, ctx.Doer), | ||||||
| 					Reaction: reaction.Type, | 					Reaction: reaction.Type, | ||||||
| @@ -430,7 +431,7 @@ func changeIssueReaction(ctx *context.APIContext, form api.EditReactionOption, i | |||||||
| 		}) | 		}) | ||||||
| 	} else { | 	} else { | ||||||
| 		// DeleteIssueReaction part | 		// DeleteIssueReaction part | ||||||
| 		err = models.DeleteIssueReaction(ctx.Doer, issue, form.Reaction) | 		err = issues_model.DeleteIssueReaction(ctx.Doer.ID, issue.ID, form.Reaction) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			ctx.Error(http.StatusInternalServerError, "DeleteIssueReaction", err) | 			ctx.Error(http.StatusInternalServerError, "DeleteIssueReaction", err) | ||||||
| 			return | 			return | ||||||
|   | |||||||
| @@ -19,6 +19,7 @@ import ( | |||||||
|  |  | ||||||
| 	"code.gitea.io/gitea/models" | 	"code.gitea.io/gitea/models" | ||||||
| 	"code.gitea.io/gitea/models/db" | 	"code.gitea.io/gitea/models/db" | ||||||
|  | 	issues_model "code.gitea.io/gitea/models/issues" | ||||||
| 	"code.gitea.io/gitea/models/organization" | 	"code.gitea.io/gitea/models/organization" | ||||||
| 	project_model "code.gitea.io/gitea/models/project" | 	project_model "code.gitea.io/gitea/models/project" | ||||||
| 	repo_model "code.gitea.io/gitea/models/repo" | 	repo_model "code.gitea.io/gitea/models/repo" | ||||||
| @@ -2349,9 +2350,9 @@ func ChangeIssueReaction(ctx *context.Context) { | |||||||
|  |  | ||||||
| 	switch ctx.Params(":action") { | 	switch ctx.Params(":action") { | ||||||
| 	case "react": | 	case "react": | ||||||
| 		reaction, err := models.CreateIssueReaction(ctx.Doer, issue, form.Content) | 		reaction, err := issues_model.CreateIssueReaction(ctx.Doer.ID, issue.ID, form.Content) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			if models.IsErrForbiddenIssueReaction(err) { | 			if issues_model.IsErrForbiddenIssueReaction(err) { | ||||||
| 				ctx.ServerError("ChangeIssueReaction", err) | 				ctx.ServerError("ChangeIssueReaction", err) | ||||||
| 				return | 				return | ||||||
| 			} | 			} | ||||||
| @@ -2367,7 +2368,7 @@ func ChangeIssueReaction(ctx *context.Context) { | |||||||
|  |  | ||||||
| 		log.Trace("Reaction for issue created: %d/%d/%d", ctx.Repo.Repository.ID, issue.ID, reaction.ID) | 		log.Trace("Reaction for issue created: %d/%d/%d", ctx.Repo.Repository.ID, issue.ID, reaction.ID) | ||||||
| 	case "unreact": | 	case "unreact": | ||||||
| 		if err := models.DeleteIssueReaction(ctx.Doer, issue, form.Content); err != nil { | 		if err := issues_model.DeleteIssueReaction(ctx.Doer.ID, issue.ID, form.Content); err != nil { | ||||||
| 			ctx.ServerError("DeleteIssueReaction", err) | 			ctx.ServerError("DeleteIssueReaction", err) | ||||||
| 			return | 			return | ||||||
| 		} | 		} | ||||||
| @@ -2451,9 +2452,9 @@ func ChangeCommentReaction(ctx *context.Context) { | |||||||
|  |  | ||||||
| 	switch ctx.Params(":action") { | 	switch ctx.Params(":action") { | ||||||
| 	case "react": | 	case "react": | ||||||
| 		reaction, err := models.CreateCommentReaction(ctx.Doer, comment.Issue, comment, form.Content) | 		reaction, err := issues_model.CreateCommentReaction(ctx.Doer.ID, comment.Issue.ID, comment.ID, form.Content) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			if models.IsErrForbiddenIssueReaction(err) { | 			if issues_model.IsErrForbiddenIssueReaction(err) { | ||||||
| 				ctx.ServerError("ChangeIssueReaction", err) | 				ctx.ServerError("ChangeIssueReaction", err) | ||||||
| 				return | 				return | ||||||
| 			} | 			} | ||||||
| @@ -2469,7 +2470,7 @@ func ChangeCommentReaction(ctx *context.Context) { | |||||||
|  |  | ||||||
| 		log.Trace("Reaction for comment created: %d/%d/%d/%d", ctx.Repo.Repository.ID, comment.Issue.ID, comment.ID, reaction.ID) | 		log.Trace("Reaction for comment created: %d/%d/%d/%d", ctx.Repo.Repository.ID, comment.Issue.ID, comment.ID, reaction.ID) | ||||||
| 	case "unreact": | 	case "unreact": | ||||||
| 		if err := models.DeleteCommentReaction(ctx.Doer, comment.Issue, comment, form.Content); err != nil { | 		if err := issues_model.DeleteCommentReaction(ctx.Doer.ID, comment.Issue.ID, comment.ID, form.Content); err != nil { | ||||||
| 			ctx.ServerError("DeleteCommentReaction", err) | 			ctx.ServerError("DeleteCommentReaction", err) | ||||||
| 			return | 			return | ||||||
| 		} | 		} | ||||||
|   | |||||||
| @@ -18,6 +18,7 @@ import ( | |||||||
| 	"code.gitea.io/gitea/models" | 	"code.gitea.io/gitea/models" | ||||||
| 	"code.gitea.io/gitea/models/db" | 	"code.gitea.io/gitea/models/db" | ||||||
| 	"code.gitea.io/gitea/models/foreignreference" | 	"code.gitea.io/gitea/models/foreignreference" | ||||||
|  | 	issues_model "code.gitea.io/gitea/models/issues" | ||||||
| 	repo_model "code.gitea.io/gitea/models/repo" | 	repo_model "code.gitea.io/gitea/models/repo" | ||||||
| 	user_model "code.gitea.io/gitea/models/user" | 	user_model "code.gitea.io/gitea/models/user" | ||||||
| 	"code.gitea.io/gitea/modules/git" | 	"code.gitea.io/gitea/modules/git" | ||||||
| @@ -392,7 +393,7 @@ func (g *GiteaLocalUploader) CreateIssues(issues ...*base.Issue) error { | |||||||
| 		} | 		} | ||||||
| 		// add reactions | 		// add reactions | ||||||
| 		for _, reaction := range issue.Reactions { | 		for _, reaction := range issue.Reactions { | ||||||
| 			res := models.Reaction{ | 			res := issues_model.Reaction{ | ||||||
| 				Type:        reaction.Content, | 				Type:        reaction.Content, | ||||||
| 				CreatedUnix: timeutil.TimeStampNow(), | 				CreatedUnix: timeutil.TimeStampNow(), | ||||||
| 			} | 			} | ||||||
| @@ -448,7 +449,7 @@ func (g *GiteaLocalUploader) CreateComments(comments ...*base.Comment) error { | |||||||
|  |  | ||||||
| 		// add reactions | 		// add reactions | ||||||
| 		for _, reaction := range comment.Reactions { | 		for _, reaction := range comment.Reactions { | ||||||
| 			res := models.Reaction{ | 			res := issues_model.Reaction{ | ||||||
| 				Type:        reaction.Content, | 				Type:        reaction.Content, | ||||||
| 				CreatedUnix: timeutil.TimeStampNow(), | 				CreatedUnix: timeutil.TimeStampNow(), | ||||||
| 			} | 			} | ||||||
| @@ -646,7 +647,7 @@ func (g *GiteaLocalUploader) newPullRequest(pr *base.PullRequest) (*models.PullR | |||||||
|  |  | ||||||
| 	// add reactions | 	// add reactions | ||||||
| 	for _, reaction := range pr.Reactions { | 	for _, reaction := range pr.Reactions { | ||||||
| 		res := models.Reaction{ | 		res := issues_model.Reaction{ | ||||||
| 			Type:        reaction.Content, | 			Type:        reaction.Content, | ||||||
| 			CreatedUnix: timeutil.TimeStampNow(), | 			CreatedUnix: timeutil.TimeStampNow(), | ||||||
| 		} | 		} | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Lunny Xiao
					Lunny Xiao