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:
Lunny Xiao 2022-03-31 17:20:39 +08:00 committed by GitHub
parent 43332a483f
commit d4f84f1c93
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 280 additions and 274 deletions

View file

@ -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 {

View file

@ -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)
}
// __________ .__ .__ __________ __ // __________ .__ .__ __________ __
// \______ \__ __| | | |\______ \ ____ ________ __ ____ _______/ |_ // \______ \__ __| | | |\______ \ ____ ________ __ ____ _______/ |_
// | ___/ | \ | | | | _// __ \/ ____/ | \_/ __ \ / ___/\ __\ // | ___/ | \ | | | | _// __ \/ ____/ | \_/ __ \ / ___/\ __\

View file

@ -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
}

View file

@ -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
} }

View file

@ -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

View file

@ -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 {

View file

@ -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 {

View file

@ -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",
)
} }

View file

@ -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
} }
@ -140,9 +200,9 @@ 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,
if opts.Doer != nil { IssueID: opts.IssueID,
reaction.UserID = opts.Doer.ID CommentID: opts.CommentID,
}
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
} }
// DeleteReaction deletes reaction for issue or comment. _, err := db.GetEngine(ctx).Where("original_author_id = 0").Delete(reaction)
func DeleteReaction(opts *ReactionOptions) error {
ctx, committer, err := db.TxContext()
if err != nil {
return err 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 }

View file

@ -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})
} }

View file

@ -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})

View file

@ -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

View file

@ -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)
} }

View file

@ -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
View 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
}

View file

@ -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

View file

@ -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
} }

View file

@ -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(),
} }