[API] Add Reactions (#9220)
* reject reactions wich ar not allowed * dont duble check CreateReaction now throw ErrForbiddenIssueReaction * add /repos/{owner}/{repo}/issues/comments/{id}/reactions endpoint * add Find Functions * fix some swagger stuff + add issue reaction endpoints + GET ReactionList now use FindReactions... * explicite Issue Only Reaction for FindReactionsOptions with "-1" commentID * load issue; load user ... * return error again * swagger def canged after LINT * check if user has ben loaded * add Tests * better way of comparing results * add suggestion * use different issue for test (dont interfear with integration test) * test dont compare Location on timeCompare * TEST: add forbidden dubble add * add comments in code to explain * add settings.UI.ReactionsMap so if !setting.UI.ReactionsMap[opts.Type] works
This commit is contained in:
parent
ee7df7ba8c
commit
37e10d4543
12 changed files with 1048 additions and 31 deletions
|
@ -1121,6 +1121,21 @@ func (err ErrNewIssueInsert) Error() string {
|
|||
return err.OriginalError.Error()
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
// __________ .__ .__ __________ __
|
||||
// \______ \__ __| | | |\______ \ ____ ________ __ ____ _______/ |_
|
||||
// | ___/ | \ | | | | _// __ \/ ____/ | \_/ __ \ / ___/\ __\
|
||||
|
|
|
@ -1 +1,39 @@
|
|||
[] # empty
|
||||
-
|
||||
id: 1 #issue reaction
|
||||
type: zzz # not allowed reaction (added before allowed reaction list has changed)
|
||||
issue_id: 1
|
||||
comment_id: 0
|
||||
user_id: 2
|
||||
created_unix: 1573248001
|
||||
|
||||
-
|
||||
id: 2 #issue reaction
|
||||
type: zzz # not allowed reaction (added before allowed reaction list has changed)
|
||||
issue_id: 1
|
||||
comment_id: 0
|
||||
user_id: 1
|
||||
created_unix: 1573248002
|
||||
|
||||
-
|
||||
id: 3 #issue reaction
|
||||
type: eyes # allowed reaction
|
||||
issue_id: 1
|
||||
comment_id: 0
|
||||
user_id: 2
|
||||
created_unix: 1573248003
|
||||
|
||||
-
|
||||
id: 4 #comment reaction
|
||||
type: laugh # allowed reaction
|
||||
issue_id: 1
|
||||
comment_id: 2
|
||||
user_id: 2
|
||||
created_unix: 1573248004
|
||||
|
||||
-
|
||||
id: 5 #comment reaction
|
||||
type: laugh # allowed reaction
|
||||
issue_id: 1
|
||||
comment_id: 2
|
||||
user_id: 1
|
||||
created_unix: 1573248005
|
||||
|
|
|
@ -33,16 +33,38 @@ type FindReactionsOptions struct {
|
|||
}
|
||||
|
||||
func (opts *FindReactionsOptions) toConds() builder.Cond {
|
||||
//If Issue ID is set add to Query
|
||||
var cond = builder.NewCond()
|
||||
if opts.IssueID > 0 {
|
||||
cond = cond.And(builder.Eq{"reaction.issue_id": opts.IssueID})
|
||||
}
|
||||
//If CommentID is > 0 add to Query
|
||||
//If it is 0 Query ignore CommentID to select
|
||||
//If it is -1 it explicit search of Issue Reactions where CommentID = 0
|
||||
if opts.CommentID > 0 {
|
||||
cond = cond.And(builder.Eq{"reaction.comment_id": opts.CommentID})
|
||||
} else if opts.CommentID == -1 {
|
||||
cond = cond.And(builder.Eq{"reaction.comment_id": 0})
|
||||
}
|
||||
|
||||
return cond
|
||||
}
|
||||
|
||||
// FindCommentReactions returns a ReactionList of all reactions from an comment
|
||||
func FindCommentReactions(comment *Comment) (ReactionList, error) {
|
||||
return findReactions(x, FindReactionsOptions{
|
||||
IssueID: comment.IssueID,
|
||||
CommentID: comment.ID})
|
||||
}
|
||||
|
||||
// FindIssueReactions returns a ReactionList of all reactions from an issue
|
||||
func FindIssueReactions(issue *Issue) (ReactionList, error) {
|
||||
return findReactions(x, FindReactionsOptions{
|
||||
IssueID: issue.ID,
|
||||
CommentID: -1,
|
||||
})
|
||||
}
|
||||
|
||||
func findReactions(e Engine, opts FindReactionsOptions) ([]*Reaction, error) {
|
||||
reactions := make([]*Reaction, 0, 10)
|
||||
sess := e.Where(opts.toConds())
|
||||
|
@ -77,6 +99,10 @@ type ReactionOptions struct {
|
|||
|
||||
// CreateReaction creates reaction for issue or comment.
|
||||
func CreateReaction(opts *ReactionOptions) (reaction *Reaction, err error) {
|
||||
if !setting.UI.ReactionsMap[opts.Type] {
|
||||
return nil, ErrForbiddenIssueReaction{opts.Type}
|
||||
}
|
||||
|
||||
sess := x.NewSession()
|
||||
defer sess.Close()
|
||||
if err = sess.Begin(); err != nil {
|
||||
|
@ -160,6 +186,19 @@ func DeleteCommentReaction(doer *User, issue *Issue, comment *Comment, content s
|
|||
})
|
||||
}
|
||||
|
||||
// LoadUser load user of reaction
|
||||
func (r *Reaction) LoadUser() (*User, error) {
|
||||
if r.User != nil {
|
||||
return r.User, nil
|
||||
}
|
||||
user, err := getUserByID(x, r.UserID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
r.User = user
|
||||
return user, nil
|
||||
}
|
||||
|
||||
// ReactionList represents list of reactions
|
||||
type ReactionList []*Reaction
|
||||
|
||||
|
|
|
@ -81,22 +81,22 @@ func TestIssueReactionCount(t *testing.T) {
|
|||
user4 := AssertExistsAndLoadBean(t, &User{ID: 4}).(*User)
|
||||
ghost := NewGhostUser()
|
||||
|
||||
issue1 := AssertExistsAndLoadBean(t, &Issue{ID: 1}).(*Issue)
|
||||
issue := AssertExistsAndLoadBean(t, &Issue{ID: 2}).(*Issue)
|
||||
|
||||
addReaction(t, user1, issue1, nil, "heart")
|
||||
addReaction(t, user2, issue1, nil, "heart")
|
||||
addReaction(t, user3, issue1, nil, "heart")
|
||||
addReaction(t, user3, issue1, nil, "+1")
|
||||
addReaction(t, user4, issue1, nil, "+1")
|
||||
addReaction(t, user4, issue1, nil, "heart")
|
||||
addReaction(t, ghost, issue1, nil, "-1")
|
||||
addReaction(t, user1, issue, nil, "heart")
|
||||
addReaction(t, user2, issue, nil, "heart")
|
||||
addReaction(t, user3, issue, nil, "heart")
|
||||
addReaction(t, user3, issue, nil, "+1")
|
||||
addReaction(t, user4, issue, nil, "+1")
|
||||
addReaction(t, user4, issue, nil, "heart")
|
||||
addReaction(t, ghost, issue, nil, "-1")
|
||||
|
||||
err := issue1.loadReactions(x)
|
||||
err := issue.loadReactions(x)
|
||||
assert.NoError(t, err)
|
||||
|
||||
assert.Len(t, issue1.Reactions, 7)
|
||||
assert.Len(t, issue.Reactions, 7)
|
||||
|
||||
reactions := issue1.Reactions.GroupByType()
|
||||
reactions := issue.Reactions.GroupByType()
|
||||
assert.Len(t, reactions["heart"], 4)
|
||||
assert.Equal(t, 2, reactions["heart"].GetMoreUserCount())
|
||||
assert.Equal(t, user1.DisplayName()+", "+user2.DisplayName(), reactions["heart"].GetFirstUsers())
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue