backport part of #9550 (#9564)

* add ErrReactionAlreadyExist
 * extend FindReactionsOptions
 * createReaction check if exit before create
This commit is contained in:
6543 2019-12-31 18:00:17 +01:00 committed by Lauris BH
parent b4b8c9679f
commit c63a80138a
3 changed files with 51 additions and 12 deletions

View File

@ -1104,6 +1104,21 @@ func (err ErrNewIssueInsert) Error() string {
return err.OriginalError.Error() return err.OriginalError.Error()
} }
// 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

@ -30,6 +30,8 @@ type Reaction struct {
type FindReactionsOptions struct { type FindReactionsOptions struct {
IssueID int64 IssueID int64
CommentID int64 CommentID int64
UserID int64
Reaction string
} }
func (opts *FindReactionsOptions) toConds() builder.Cond { func (opts *FindReactionsOptions) toConds() builder.Cond {
@ -40,6 +42,13 @@ func (opts *FindReactionsOptions) toConds() builder.Cond {
if opts.CommentID > 0 { if opts.CommentID > 0 {
cond = cond.And(builder.Eq{"reaction.comment_id": opts.CommentID}) cond = cond.And(builder.Eq{"reaction.comment_id": opts.CommentID})
} }
if opts.UserID > 0 {
cond = cond.And(builder.Eq{"reaction.user_id": opts.UserID})
}
if opts.Reaction != "" {
cond = cond.And(builder.Eq{"reaction.type": opts.Reaction})
}
return cond return cond
} }
@ -57,9 +66,25 @@ func createReaction(e *xorm.Session, opts *ReactionOptions) (*Reaction, error) {
UserID: opts.Doer.ID, UserID: opts.Doer.ID,
IssueID: opts.Issue.ID, IssueID: opts.Issue.ID,
} }
findOpts := FindReactionsOptions{
IssueID: opts.Issue.ID,
CommentID: -1, // reaction to issue only
Reaction: opts.Type,
UserID: opts.Doer.ID,
}
if opts.Comment != nil { if opts.Comment != nil {
reaction.CommentID = opts.Comment.ID reaction.CommentID = opts.Comment.ID
findOpts.CommentID = opts.Comment.ID
} }
existingR, err := findReactions(e, findOpts)
if err != nil {
return nil, err
}
if len(existingR) > 0 {
return existingR[0], ErrReactionAlreadyExist{Reaction: opts.Type}
}
if _, err := e.Insert(reaction); err != nil { if _, err := e.Insert(reaction); err != nil {
return nil, err return nil, err
} }
@ -76,19 +101,19 @@ type ReactionOptions struct {
} }
// CreateReaction creates reaction for issue or comment. // CreateReaction creates reaction for issue or comment.
func CreateReaction(opts *ReactionOptions) (reaction *Reaction, err error) { func CreateReaction(opts *ReactionOptions) (*Reaction, error) {
sess := x.NewSession() sess := x.NewSession()
defer sess.Close() defer sess.Close()
if err = sess.Begin(); err != nil { if err := sess.Begin(); err != nil {
return nil, err return nil, err
} }
reaction, err = createReaction(sess, opts) reaction, err := createReaction(sess, opts)
if err != nil { if err != nil {
return nil, err return reaction, err
} }
if err = sess.Commit(); err != nil { if err := sess.Commit(); err != nil {
return nil, err return nil, err
} }
return reaction, nil return reaction, nil

View File

@ -50,9 +50,10 @@ func TestIssueAddDuplicateReaction(t *testing.T) {
Type: "heart", Type: "heart",
}) })
assert.Error(t, err) assert.Error(t, err)
assert.Nil(t, reaction) assert.Equal(t, ErrReactionAlreadyExist{Reaction: "heart"}, err)
AssertExistsAndLoadBean(t, &Reaction{Type: "heart", UserID: user1.ID, IssueID: issue1.ID}) existingR := AssertExistsAndLoadBean(t, &Reaction{Type: "heart", UserID: user1.ID, IssueID: issue1.ID}).(*Reaction)
assert.Equal(t, existingR.ID, reaction.ID)
} }
func TestIssueDeleteReaction(t *testing.T) { func TestIssueDeleteReaction(t *testing.T) {
@ -129,7 +130,6 @@ func TestIssueCommentDeleteReaction(t *testing.T) {
user2 := AssertExistsAndLoadBean(t, &User{ID: 2}).(*User) user2 := AssertExistsAndLoadBean(t, &User{ID: 2}).(*User)
user3 := AssertExistsAndLoadBean(t, &User{ID: 3}).(*User) user3 := AssertExistsAndLoadBean(t, &User{ID: 3}).(*User)
user4 := AssertExistsAndLoadBean(t, &User{ID: 4}).(*User) user4 := AssertExistsAndLoadBean(t, &User{ID: 4}).(*User)
ghost := NewGhostUser()
issue1 := AssertExistsAndLoadBean(t, &Issue{ID: 1}).(*Issue) issue1 := AssertExistsAndLoadBean(t, &Issue{ID: 1}).(*Issue)
@ -139,14 +139,13 @@ func TestIssueCommentDeleteReaction(t *testing.T) {
addReaction(t, user2, issue1, comment1, "heart") addReaction(t, user2, issue1, comment1, "heart")
addReaction(t, user3, issue1, comment1, "heart") addReaction(t, user3, issue1, comment1, "heart")
addReaction(t, user4, issue1, comment1, "+1") addReaction(t, user4, issue1, comment1, "+1")
addReaction(t, ghost, issue1, comment1, "heart")
err := comment1.LoadReactions() err := comment1.LoadReactions()
assert.NoError(t, err) assert.NoError(t, err)
assert.Len(t, comment1.Reactions, 5) assert.Len(t, comment1.Reactions, 4)
reactions := comment1.Reactions.GroupByType() reactions := comment1.Reactions.GroupByType()
assert.Len(t, reactions["heart"], 4) assert.Len(t, reactions["heart"], 3)
assert.Len(t, reactions["+1"], 1) assert.Len(t, reactions["+1"], 1)
} }
@ -160,7 +159,7 @@ func TestIssueCommentReactionCount(t *testing.T) {
comment1 := AssertExistsAndLoadBean(t, &Comment{ID: 1}).(*Comment) comment1 := AssertExistsAndLoadBean(t, &Comment{ID: 1}).(*Comment)
addReaction(t, user1, issue1, comment1, "heart") addReaction(t, user1, issue1, comment1, "heart")
DeleteCommentReaction(user1, issue1, comment1, "heart") assert.NoError(t, DeleteCommentReaction(user1, issue1, comment1, "heart"))
AssertNotExistsBean(t, &Reaction{Type: "heart", UserID: user1.ID, IssueID: issue1.ID, CommentID: comment1.ID}) AssertNotExistsBean(t, &Reaction{Type: "heart", UserID: user1.ID, IssueID: issue1.ID, CommentID: comment1.ID})
} }