diff --git a/backend/app/store/service/service.go b/backend/app/store/service/service.go index e35156be..495b10b7 100644 --- a/backend/app/store/service/service.go +++ b/backend/app/store/service/service.go @@ -315,7 +315,7 @@ func (s *DataStore) Vote(req VoteReq) (comment store.Comment, err error) { } v, voted := comment.Votes[req.UserID] - if voted && v == req.Val { + if voted && v == req.Val { // voted before and same vote (+/-) again. Change allowed, i.e. +, - or -, + is fine return comment, errors.Errorf("user %s already voted for %s", req.UserID, req.CommentID) } @@ -341,9 +341,16 @@ func (s *DataStore) Vote(req VoteReq) (comment store.Comment, err error) { return comment, errors.Errorf("minimal score reached for comment %s", req.CommentID) } - // reset vote if user changed to opposite + // add ip hash to voted ip map + if comment.VotedIPs == nil { + comment.VotedIPs = map[string]store.VotedIPInfo{} + } + comment.VotedIPs[userIPHash] = store.VotedIPInfo{Timestamp: time.Now(), Value: req.Val} + + // reset vote if user changed to opposite. Effectively it is "forget about prev votes" to allow "+ - -" or "- + +" corrections if voted && v != req.Val { delete(comment.Votes, req.UserID) + delete(comment.VotedIPs, userIPHash) } // add to voted map if first vote @@ -351,13 +358,6 @@ func (s *DataStore) Vote(req VoteReq) (comment store.Comment, err error) { comment.Votes[req.UserID] = req.Val } - // add ip hash to voted ip map - if comment.VotedIPs == nil { - comment.VotedIPs = map[string]store.VotedIPInfo{} - } - - comment.VotedIPs[userIPHash] = store.VotedIPInfo{Timestamp: time.Now(), Value: req.Val} - // update score if req.Val { comment.Score++ diff --git a/backend/app/store/service/service_test.go b/backend/app/store/service/service_test.go index be4b0372..dcbf9d75 100644 --- a/backend/app/store/service/service_test.go +++ b/backend/app/store/service/service_test.go @@ -455,7 +455,29 @@ func TestService_VotePositive(t *testing.T) { assert.NoError(t, err, "minimal score doesn't affect positive vote") assert.Equal(t, 1, c.Score) - b.PositiveScore = false // allow negative voting + c, err = b.Vote(VoteReq{Locator: store.Locator{URL: "https://radio-t.com", SiteID: "radio-t"}, CommentID: "id-1", + UserID: "user2", Val: true}) + assert.NoError(t, err, "vote set to +2") + assert.Equal(t, 2, c.Score) + + // check +, -, - + c, err = b.Vote(VoteReq{Locator: store.Locator{URL: "https://radio-t.com", SiteID: "radio-t"}, CommentID: "id-1", + UserID: "user5", Val: true}) + assert.NoError(t, err, "user5 +1, score 3") + assert.Equal(t, 3, c.Score) + + c, err = b.Vote(VoteReq{Locator: store.Locator{URL: "https://radio-t.com", SiteID: "radio-t"}, CommentID: "id-1", + UserID: "user5", Val: false}) + assert.NoError(t, err, "user5 -1, score reset to 2") + assert.Equal(t, 2, c.Score) + + c, err = b.Vote(VoteReq{Locator: store.Locator{URL: "https://radio-t.com", SiteID: "radio-t"}, CommentID: "id-1", + UserID: "user5", Val: false}) + assert.NoError(t, err, "user5 -1, score 1") + assert.Equal(t, 1, c.Score) + + // allow negative voting + b.PositiveScore = false c, err = b.Vote(VoteReq{Locator: store.Locator{URL: "https://radio-t.com", SiteID: "radio-t"}, CommentID: "id-1", UserID: "user2", Val: false}) assert.NoError(t, err, "minimal score ignored") @@ -504,8 +526,7 @@ func TestService_VoteSameIP(t *testing.T) { eng, teardown := prepStoreEngine(t) defer teardown() - b := DataStore{Engine: eng, AdminStore: admin.NewStaticKeyStore("secret 123"), - MaxVotes: -1} + b := DataStore{Engine: eng, AdminStore: admin.NewStaticKeyStore("secret 123"), MaxVotes: -1} b.RestrictSameIPVotes.Enabled = true c, err := b.Vote(VoteReq{Locator: store.Locator{URL: "https://radio-t.com", SiteID: "radio-t"}, CommentID: "id-2", @@ -516,12 +537,17 @@ func TestService_VoteSameIP(t *testing.T) { c, err = b.Vote(VoteReq{Locator: store.Locator{URL: "https://radio-t.com", SiteID: "radio-t"}, CommentID: "id-2", UserID: "user3", UserIP: "123", Val: true}) assert.EqualError(t, err, "the same ip cce61be6e0a692420ae0de31dceca179123c3b8a already voted for id-2") - assert.Equal(t, 1, c.Score, "still have 1 score") + assert.Equal(t, 1, c.Score, "still have 1 score, rejected") c, err = b.Vote(VoteReq{Locator: store.Locator{URL: "https://radio-t.com", SiteID: "radio-t"}, CommentID: "id-2", - UserID: "user3", UserIP: "123", Val: false}) + UserID: "user2", UserIP: "123", Val: false}) assert.NoError(t, err) assert.Equal(t, 0, c.Score, "reset to 0 score, opposite vote allowed") + + c, err = b.Vote(VoteReq{Locator: store.Locator{URL: "https://radio-t.com", SiteID: "radio-t"}, CommentID: "id-2", + UserID: "user2", UserIP: "123", Val: false}) + assert.NoError(t, err) + assert.Equal(t, -1, c.Score, "set to -1 score, correction vote allowed") } func TestService_VoteSameIPWithDuration(t *testing.T) {