added maximum votes limit per comment (#223)

* added maximum votes limit per comment

* added 'max-votes' param description into README
This commit is contained in:
Aleksandr Melnikov
2018-11-23 17:47:42 -06:00
committed by Umputun
parent 11d8338989
commit f8e36551ea
4 changed files with 32 additions and 0 deletions
+1
View File
@@ -124,6 +124,7 @@ _this is the recommended way to run remark42_
| ssl.cert | SSL_CERT | | path to cert.pem file |
| ssl.key | SSL_KEY | | path to key.pem file |
| max-comment | MAX_COMMENT_SIZE | 2048 | comment's size limit |
| max-votes | MAX_VOTES | `-1` | votes limit per comment, `-1` - unlimited |
| low-score | LOW_SCORE | `-5` | low score threshold |
| critical-score | CRITICAL_SCORE | `-10` | critical score threshold |
| edit-time | EDIT_TIME | `5m` | edit window |
+2
View File
@@ -45,6 +45,7 @@ type ServerCommand struct {
MaxBackupFiles int `long:"max-back" env:"MAX_BACKUP_FILES" default:"10" description:"max backups to keep"`
ImageProxy bool `long:"img-proxy" env:"IMG_PROXY" description:"enable image proxy"`
MaxCommentSize int `long:"max-comment" env:"MAX_COMMENT_SIZE" default:"2048" description:"max comment size"`
MaxVotes int `long:"max-votes" env:"MAX_VOTES" default:"-1" description:"maximum number of votes per comment"`
LowScore int `long:"low-score" env:"LOW_SCORE" default:"-5" description:"low score threshold"`
CriticalScore int `long:"critical-score" env:"CRITICAL_SCORE" default:"-10" description:"critical score threshold"`
ReadOnlyAge int `long:"read-age" env:"READONLY_AGE" default:"0" description:"read-only age of comments"`
@@ -206,6 +207,7 @@ func (s *ServerCommand) newServerApp() (*serverApp, error) {
EditDuration: s.EditDuration,
AdminStore: adminStore,
MaxCommentSize: s.MaxCommentSize,
MaxVotes: s.MaxVotes,
}
loadingCache, err := s.makeCache()
+11
View File
@@ -18,6 +18,7 @@ type DataStore struct {
EditDuration time.Duration
AdminStore admin.Store
MaxCommentSize int
MaxVotes int
// granular locks
scopedLocks struct {
@@ -28,6 +29,7 @@ type DataStore struct {
}
const defaultCommentMaxSize = 2000
const defaultVotesLimit = -1 // unlimited
// Create prepares comment and forward to Interface.Create
func (s *DataStore) Create(comment store.Comment) (commentID string, err error) {
@@ -97,6 +99,15 @@ func (s *DataStore) Vote(locator store.Locator, commentID string, userID string,
return comment, errors.Errorf("user %s already voted for %s", userID, commentID)
}
maxVotes := s.MaxVotes
if s.MaxVotes <= 0 {
maxVotes = defaultVotesLimit
}
if maxVotes >= 0 && len(comment.Votes) >= maxVotes {
return comment, errors.Errorf("maximum number of votes exceeded for comment %s", commentID)
}
// reset vote if user changed to opposite
if voted && v != val {
delete(comment.Votes, userID)
+18
View File
@@ -116,6 +116,24 @@ func TestService_Vote(t *testing.T) {
assert.Equal(t, map[string]bool{}, res[0].Votes, "vote reset ok")
}
func TestService_VoteLimit(t *testing.T) {
defer os.Remove(testDb)
b := DataStore{Interface: prepStoreEngine(t), AdminStore: admin.NewStaticKeyStore("secret 123"), MaxVotes: 2}
_, err := b.Vote(store.Locator{URL: "https://radio-t.com", SiteID: "radio-t"}, "id-1", "user2", true)
assert.Nil(t, err)
_, err = b.Vote(store.Locator{URL: "https://radio-t.com", SiteID: "radio-t"}, "id-1", "user3", true)
assert.Nil(t, err)
_, err = b.Vote(store.Locator{URL: "https://radio-t.com", SiteID: "radio-t"}, "id-1", "user4", true)
assert.NotNil(t, err, "vote limit reached")
assert.True(t, strings.HasPrefix(err.Error(), "maximum number of votes exceeded for comment id-1"))
_, err = b.Vote(store.Locator{URL: "https://radio-t.com", SiteID: "radio-t"}, "id-2", "user4", true)
assert.Nil(t, err)
}
func TestService_VoteAggressive(t *testing.T) {
defer os.Remove(testDb)
b := DataStore{Interface: prepStoreEngine(t), AdminStore: admin.NewStaticKeyStore("secret 123")}