swtich commentID to strings
This commit is contained in:
+3
-10
@@ -3,7 +3,6 @@ package rest
|
||||
import (
|
||||
"log"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/go-chi/chi"
|
||||
"github.com/go-chi/render"
|
||||
@@ -25,17 +24,11 @@ func (m *moderator) routes() chi.Router {
|
||||
// DELETE /comment/{id}?url=post-url
|
||||
func (m *moderator) deleteCommentCtrl(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
id, err := strconv.ParseInt(chi.URLParam(r, "id"), 10, 64)
|
||||
if err != nil {
|
||||
log.Printf("[WARN] bad id %s", chi.URLParam(r, "id"))
|
||||
httpError(w, r, http.StatusBadRequest, err, "can't parse id")
|
||||
return
|
||||
}
|
||||
|
||||
log.Printf("[INFO] delete comment %d", id)
|
||||
id := chi.URLParam(r, "id")
|
||||
log.Printf("[INFO] delete comment %s", id)
|
||||
|
||||
url := r.URL.Query().Get("url")
|
||||
err = m.dataStore.Delete(store.Locator{URL: url}, id)
|
||||
err := m.dataStore.Delete(store.Locator{URL: url}, id)
|
||||
if err != nil {
|
||||
log.Printf("[WARN] can't delete comment, %s", err)
|
||||
httpError(w, r, http.StatusInternalServerError, err, "can't delete comment")
|
||||
|
||||
+6
-21
@@ -54,7 +54,6 @@ func (s *Server) Run() {
|
||||
rauth.Post("/comment", s.createCommentCtrl)
|
||||
rauth.Get("/user", s.getUserInfo)
|
||||
rauth.Put("/vote/{id}", s.voteCtrl)
|
||||
//rauth.With(AdminOnly).Delete("/comment/{id}", s.deleteCommentCtrl)
|
||||
})
|
||||
|
||||
rapi.With(Auth(s.SessionStore, s.Admins, s.DevMode)).Group(func(rmoder chi.Router) {
|
||||
@@ -136,16 +135,11 @@ func (s *Server) createCommentCtrl(w http.ResponseWriter, r *http.Request) {
|
||||
// DELETE /comment/{id}?url=post-url
|
||||
func (s *Server) deleteCommentCtrl(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
id, err := strconv.ParseInt(chi.URLParam(r, "id"), 10, 64)
|
||||
if err != nil {
|
||||
log.Printf("[WARN] bad id %s", chi.URLParam(r, "id"))
|
||||
httpError(w, r, http.StatusBadRequest, err, "can't parse id")
|
||||
}
|
||||
|
||||
log.Printf("[INFO] delete comment %d", id)
|
||||
id := chi.URLParam(r, "id")
|
||||
log.Printf("[INFO] delete comment %s", id)
|
||||
|
||||
url := r.URL.Query().Get("url")
|
||||
err = s.Store.Delete(store.Locator{URL: url}, id)
|
||||
err := s.Store.Delete(store.Locator{URL: url}, id)
|
||||
if err != nil {
|
||||
log.Printf("[WARN] can't delete comment, %s", err)
|
||||
httpError(w, r, http.StatusInternalServerError, err, "can't delete comment")
|
||||
@@ -193,14 +187,10 @@ func (s *Server) getLastComments(w http.ResponseWriter, r *http.Request) {
|
||||
// GET /id/{id}?url=post-url
|
||||
func (s *Server) getByID(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
id, err := strconv.ParseInt(chi.URLParam(r, "id"), 10, 64)
|
||||
if err != nil {
|
||||
log.Printf("[WARN] bad id %s", chi.URLParam(r, "id"))
|
||||
httpError(w, r, http.StatusBadRequest, err, "can't parse id")
|
||||
}
|
||||
id := chi.URLParam(r, "id")
|
||||
url := r.URL.Query().Get("url")
|
||||
|
||||
log.Printf("[INFO] get comments by id %d, %s", id, url)
|
||||
log.Printf("[INFO] get comments by id %s, %s", id, url)
|
||||
|
||||
comment, err := s.Store.Get(store.Locator{URL: url}, id)
|
||||
if err != nil {
|
||||
@@ -243,12 +233,7 @@ func (s *Server) voteCtrl(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
id, err := strconv.ParseInt(chi.URLParam(r, "id"), 10, 64)
|
||||
if err != nil {
|
||||
log.Printf("[WARN] bad id %s", chi.URLParam(r, "id"))
|
||||
httpError(w, r, http.StatusBadRequest, err, "can't parse id")
|
||||
}
|
||||
|
||||
id := chi.URLParam(r, "id")
|
||||
log.Printf("[INFO] vote for comment %d", id)
|
||||
|
||||
url := r.URL.Query().Get("url")
|
||||
|
||||
+31
-43
@@ -4,10 +4,11 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"sort"
|
||||
|
||||
"github.com/boltdb/bolt"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
@@ -38,9 +39,9 @@ func NewBoltDB(dbFile string) (*BoltDB, error) {
|
||||
}
|
||||
|
||||
// Create saves new comment to store
|
||||
func (b *BoltDB) Create(comment Comment) (int64, error) {
|
||||
func (b *BoltDB) Create(comment Comment) (string, error) {
|
||||
|
||||
comment.ID = time.Now().UnixNano()
|
||||
comment.ID = makeCommentID()
|
||||
comment.Timestamp = time.Now()
|
||||
comment.Votes = make(map[string]bool)
|
||||
|
||||
@@ -51,9 +52,8 @@ func (b *BoltDB) Create(comment Comment) (int64, error) {
|
||||
}
|
||||
|
||||
// check if key already in store, reject doubles
|
||||
key := b.keyFromComment(comment)
|
||||
if bucket.Get(key) != nil {
|
||||
return errors.Errorf("key %s already in store", string(key))
|
||||
if bucket.Get([]byte(comment.ID)) != nil {
|
||||
return errors.Errorf("key %s already in store", comment.ID)
|
||||
}
|
||||
|
||||
// serialise comment to json's []byte for bolt and save
|
||||
@@ -62,8 +62,8 @@ func (b *BoltDB) Create(comment Comment) (int64, error) {
|
||||
return errors.Wrap(jerr, "can't marshal comment")
|
||||
}
|
||||
|
||||
if err := bucket.Put(key, jdata); err != nil {
|
||||
return errors.Wrapf(err, "failed to put key %s", string(key))
|
||||
if err := bucket.Put([]byte(comment.ID), jdata); err != nil {
|
||||
return errors.Wrapf(err, "failed to put key %s", comment.ID)
|
||||
}
|
||||
|
||||
// add reference to comment to "last" bucket
|
||||
@@ -73,7 +73,7 @@ func (b *BoltDB) Create(comment Comment) (int64, error) {
|
||||
}
|
||||
|
||||
rv := refFromComment(comment)
|
||||
e = bucket.Put(b.keyFromValue(comment.ID), []byte(rv.value()))
|
||||
e = bucket.Put([]byte(comment.ID), []byte(rv.value()))
|
||||
if e != nil {
|
||||
return errors.Wrapf(e, "can't put reference %s to %s", rv.value(), lastBucketName)
|
||||
}
|
||||
@@ -84,17 +84,16 @@ func (b *BoltDB) Create(comment Comment) (int64, error) {
|
||||
return comment.ID, err
|
||||
}
|
||||
|
||||
// Delete removed comment by url and id from the store
|
||||
func (b *BoltDB) Delete(locator Locator, id int64) error {
|
||||
// Delete removes comment by url and comment id from the store
|
||||
func (b *BoltDB) Delete(locator Locator, commentID string) error {
|
||||
|
||||
return b.Update(func(tx *bolt.Tx) error {
|
||||
bucket := tx.Bucket([]byte(locator.URL))
|
||||
if bucket == nil {
|
||||
return errors.Errorf("no bucket %s in store", locator.URL)
|
||||
}
|
||||
key := b.keyFromValue(id)
|
||||
if err := bucket.Delete(key); err != nil {
|
||||
return errors.Wrapf(err, "can't delete key %s from bucket %s", key, locator.URL)
|
||||
if err := bucket.Delete([]byte(commentID)); err != nil {
|
||||
return errors.Wrapf(err, "can't delete key %s from bucket %s", commentID, locator.URL)
|
||||
}
|
||||
|
||||
// delete from "last" bucket
|
||||
@@ -103,8 +102,8 @@ func (b *BoltDB) Delete(locator Locator, id int64) error {
|
||||
return errors.Errorf("no bucket %s in store", lastBucketName)
|
||||
}
|
||||
|
||||
if err := bucket.Delete(key); err != nil {
|
||||
return errors.Wrapf(err, "can't delete key %s from bucket %s", key, lastBucketName)
|
||||
if err := bucket.Delete([]byte(commentID)); err != nil {
|
||||
return errors.Wrapf(err, "can't delete key %s from bucket %s", commentID, lastBucketName)
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -131,11 +130,12 @@ func (b *BoltDB) Find(request Request) ([]Comment, error) {
|
||||
})
|
||||
})
|
||||
|
||||
sort.Slice(res, func(i, j int) bool { return res[i].Timestamp.Before(res[j].Timestamp) })
|
||||
return res, err
|
||||
}
|
||||
|
||||
// Get comment by id
|
||||
func (b *BoltDB) Get(locator Locator, id int64) (comment Comment, err error) {
|
||||
func (b *BoltDB) Get(locator Locator, commentID string) (comment Comment, err error) {
|
||||
err = b.View(func(tx *bolt.Tx) error {
|
||||
|
||||
lastBucket := tx.Bucket([]byte(lastBucketName))
|
||||
@@ -150,14 +150,14 @@ func (b *BoltDB) Get(locator Locator, id int64) (comment Comment, err error) {
|
||||
return e
|
||||
}
|
||||
|
||||
if foundID == id && url == locator.URL {
|
||||
if foundID == commentID && url == locator.URL {
|
||||
urlBucket := tx.Bucket([]byte(url))
|
||||
if urlBucket == nil {
|
||||
return errors.Errorf("no bucket %s in store", url)
|
||||
}
|
||||
commentVal := urlBucket.Get(b.keyFromValue(id))
|
||||
commentVal := urlBucket.Get([]byte(commentID))
|
||||
if commentVal == nil {
|
||||
return errors.Errorf("no comment for %d in store %s", id, url)
|
||||
return errors.Errorf("no comment for %d in store %s", commentID, url)
|
||||
}
|
||||
|
||||
if e := json.Unmarshal(commentVal, &comment); e != nil {
|
||||
@@ -166,7 +166,7 @@ func (b *BoltDB) Get(locator Locator, id int64) (comment Comment, err error) {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return errors.Errorf("no id %d in store %s", id, locator.URL)
|
||||
return errors.Errorf("no id %d in store %s", commentID, locator.URL)
|
||||
})
|
||||
|
||||
return comment, err
|
||||
@@ -183,7 +183,7 @@ func (b *BoltDB) Last(locator Locator, max int) (result []Comment, err error) {
|
||||
|
||||
c := lastBucket.Cursor()
|
||||
for k, v := c.Last(); k != nil; k, v = c.Prev() {
|
||||
url, id, e := refFromValue(v).parse()
|
||||
url, commentID, e := refFromValue(v).parse()
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
@@ -191,9 +191,9 @@ func (b *BoltDB) Last(locator Locator, max int) (result []Comment, err error) {
|
||||
if urlBucket == nil {
|
||||
return errors.Errorf("no bucket %s in store", url)
|
||||
}
|
||||
commentVal := urlBucket.Get(b.keyFromValue(id))
|
||||
commentVal := urlBucket.Get([]byte(commentID))
|
||||
if commentVal == nil {
|
||||
log.Printf("[WARN] no comment for %d in store %s", id, url)
|
||||
log.Printf("[WARN] no comment for %d in store %s", commentID, url)
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -213,7 +213,7 @@ func (b *BoltDB) Last(locator Locator, max int) (result []Comment, err error) {
|
||||
}
|
||||
|
||||
// Vote for comment by id and locator
|
||||
func (b *BoltDB) Vote(locator Locator, commentID int64, userID string, val bool) (comment Comment, err error) {
|
||||
func (b *BoltDB) Vote(locator Locator, commentID string, userID string, val bool) (comment Comment, err error) {
|
||||
|
||||
err = b.Update(func(tx *bolt.Tx) error {
|
||||
bucket := tx.Bucket([]byte(locator.URL))
|
||||
@@ -222,7 +222,7 @@ func (b *BoltDB) Vote(locator Locator, commentID int64, userID string, val bool)
|
||||
}
|
||||
|
||||
// get and unmarshal comment for the store
|
||||
commentVal := bucket.Get(b.keyFromValue(commentID))
|
||||
commentVal := bucket.Get([]byte(commentID))
|
||||
if commentVal == nil {
|
||||
return errors.Errorf("no comment for %d in store %s", commentID, locator.URL)
|
||||
}
|
||||
@@ -249,7 +249,7 @@ func (b *BoltDB) Vote(locator Locator, commentID int64, userID string, val bool)
|
||||
if e != nil {
|
||||
return errors.Wrap(e, "can't marshal comment with updated votes")
|
||||
}
|
||||
if e = bucket.Put(b.keyFromValue(commentID), data); e != nil {
|
||||
if e = bucket.Put([]byte(commentID), data); e != nil {
|
||||
return errors.Wrap(e, "failed to save comment with updated votes")
|
||||
}
|
||||
return nil
|
||||
@@ -315,14 +315,6 @@ func (b *BoltDB) bucketForBlock(locator Locator, userID string) []byte {
|
||||
return []byte(fmt.Sprintf("%s%s", blocksBucketPrefix, locator.SiteID))
|
||||
}
|
||||
|
||||
func (b *BoltDB) keyFromComment(comment Comment) []byte {
|
||||
return []byte(fmt.Sprintf("%22d", comment.ID))
|
||||
}
|
||||
|
||||
func (b *BoltDB) keyFromValue(id int64) []byte {
|
||||
return []byte(fmt.Sprintf("%22d", id))
|
||||
}
|
||||
|
||||
// buckets returns list of buckets, which is list of all commented posts
|
||||
func (b BoltDB) buckets() (result []string) {
|
||||
|
||||
@@ -338,7 +330,7 @@ func (b BoltDB) buckets() (result []string) {
|
||||
type ref string
|
||||
|
||||
func refFromComment(comment Comment) *ref {
|
||||
result := ref(fmt.Sprintf("%s!!%d", comment.Locator.URL, comment.ID))
|
||||
result := ref(fmt.Sprintf("%s!!%s", comment.Locator.URL, comment.ID))
|
||||
return &result
|
||||
}
|
||||
|
||||
@@ -349,14 +341,10 @@ func refFromValue(val []byte) *ref {
|
||||
|
||||
func (r ref) value() string { return string(r) }
|
||||
|
||||
func (r ref) parse() (url string, id int64, err error) {
|
||||
func (r ref) parse() (url string, commentID string, err error) {
|
||||
elems := strings.Split(string(r), "!!")
|
||||
if len(elems) < 2 {
|
||||
return "", 0, errors.Errorf("can't parse ref %s", r)
|
||||
return "", "", errors.Errorf("can't parse ref %s", r)
|
||||
}
|
||||
url = elems[0]
|
||||
if id, err = strconv.ParseInt(elems[1], 10, 64); err != nil {
|
||||
return "", 0, errors.Wrapf(err, "can't extract id from ref %s", r)
|
||||
}
|
||||
return url, id, nil
|
||||
return elems[0], elems[1], nil
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@ func TestBoltDB_Get(t *testing.T) {
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, "some text2", comment.Text)
|
||||
|
||||
comment, err = b.Get(Locator{URL: "https://radio-t.com"}, 1234567)
|
||||
comment, err = b.Get(Locator{URL: "https://radio-t.com"}, "1234567")
|
||||
assert.NotNil(t, err)
|
||||
}
|
||||
|
||||
|
||||
+26
-8
@@ -1,11 +1,17 @@
|
||||
package store
|
||||
|
||||
import "time"
|
||||
import (
|
||||
"crypto/rand"
|
||||
"crypto/sha1"
|
||||
"fmt"
|
||||
"log"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Comment represents a single comment with reference to its parent
|
||||
// Comment represents a single comment with optinal reference to its parent
|
||||
type Comment struct {
|
||||
ID int64 `json:"id"`
|
||||
ParentID int64 `json:"pid"`
|
||||
ID string `json:"id"`
|
||||
ParentID string `json:"pid"`
|
||||
Text string `json:"text"`
|
||||
User User `json:"user"`
|
||||
Locator Locator `json:"locator"`
|
||||
@@ -40,14 +46,26 @@ type Request struct {
|
||||
|
||||
// Interface defines basic CRUD for comments
|
||||
type Interface interface {
|
||||
Create(comment Comment) (int64, error)
|
||||
Delete(locator Locator, id int64) error
|
||||
Create(comment Comment) (commentID string, err error)
|
||||
Delete(locator Locator, commentID string) error
|
||||
Find(request Request) ([]Comment, error)
|
||||
Last(locator Locator, max int) ([]Comment, error)
|
||||
Get(locator Locator, id int64) (Comment, error)
|
||||
Vote(locator Locator, commentID int64, userID string, val bool) (Comment, error)
|
||||
Get(locator Locator, commentID string) (Comment, error)
|
||||
Vote(locator Locator, commentID string, userID string, val bool) (Comment, error)
|
||||
Count(locator Locator) (int, error)
|
||||
|
||||
SetBlock(locator Locator, userID string, status bool) error
|
||||
IsBlocked(locator Locator, userID string) bool
|
||||
}
|
||||
|
||||
func makeCommentID() string {
|
||||
b := make([]byte, 64)
|
||||
if _, err := rand.Read(b); err != nil {
|
||||
log.Fatalf("[ERROR] can't get randoms, %s", err)
|
||||
}
|
||||
s := sha1.New()
|
||||
if _, err := s.Write(b); err != nil {
|
||||
log.Fatalf("[ERROR] can't make sha1 for random, %s", err)
|
||||
}
|
||||
return fmt.Sprintf("%x", s.Sum(nil))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user