add service layer on top of store
This commit is contained in:
+2
-1
@@ -72,12 +72,13 @@ func main() {
|
||||
return
|
||||
}
|
||||
|
||||
dataService := store.Service{Interface: dataStore}
|
||||
sessionStore := sessions.NewFilesystemStore(opts.ServerCommand.SessionStore, []byte(opts.ServerCommand.StoreKey))
|
||||
exporter := migrator.Remark{DataStore: dataStore}
|
||||
|
||||
srv := rest.Server{
|
||||
Version: revision,
|
||||
Store: dataStore,
|
||||
DataService: dataService,
|
||||
SessionStore: sessionStore,
|
||||
Admins: opts.Admins,
|
||||
DevMode: opts.DevMode,
|
||||
|
||||
+7
-7
@@ -15,9 +15,9 @@ import (
|
||||
|
||||
// admin provides router for all requests available for admin only
|
||||
type admin struct {
|
||||
dataStore store.Interface
|
||||
exporter migrator.Exporter
|
||||
respCache *cache.Cache
|
||||
dataService store.Service
|
||||
exporter migrator.Exporter
|
||||
respCache *cache.Cache
|
||||
}
|
||||
|
||||
func (a *admin) routes() chi.Router {
|
||||
@@ -37,7 +37,7 @@ func (a *admin) deleteCommentCtrl(w http.ResponseWriter, r *http.Request) {
|
||||
log.Printf("[INFO] delete comment %s", id)
|
||||
|
||||
url := r.URL.Query().Get("url")
|
||||
err := a.dataStore.Delete(store.Locator{URL: url}, id)
|
||||
err := a.dataService.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")
|
||||
@@ -54,7 +54,7 @@ func (a *admin) setBlockCtrl(w http.ResponseWriter, r *http.Request) {
|
||||
siteID := r.URL.Query().Get("site")
|
||||
blockStatus := r.URL.Query().Get("block") == "1"
|
||||
|
||||
if err := a.dataStore.SetBlock(store.Locator{SiteID: siteID}, userID, blockStatus); err != nil {
|
||||
if err := a.dataService.SetBlock(store.Locator{SiteID: siteID}, userID, blockStatus); err != nil {
|
||||
httpError(w, r, http.StatusBadRequest, err, "can't set blocking status")
|
||||
return
|
||||
}
|
||||
@@ -68,7 +68,7 @@ func (a *admin) setPinCtrl(w http.ResponseWriter, r *http.Request) {
|
||||
url := r.URL.Query().Get("url")
|
||||
pinStatus := r.URL.Query().Get("pin") == "1"
|
||||
|
||||
if err := a.dataStore.SetPin(store.Locator{URL: url}, commentID, pinStatus); err != nil {
|
||||
if err := a.dataService.SetPin(store.Locator{URL: url}, commentID, pinStatus); err != nil {
|
||||
httpError(w, r, http.StatusBadRequest, err, "can't set pin status")
|
||||
return
|
||||
}
|
||||
@@ -84,5 +84,5 @@ func (a *admin) exportCtrl(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
func (a *admin) checkBlocked(locator store.Locator, user store.User) bool {
|
||||
return a.dataStore.IsBlocked(store.Locator{}, user.ID)
|
||||
return a.dataService.IsBlocked(store.Locator{}, user.ID)
|
||||
}
|
||||
|
||||
+10
-10
@@ -27,7 +27,7 @@ import (
|
||||
// Server is a rest access server
|
||||
type Server struct {
|
||||
Version string
|
||||
Store store.Interface
|
||||
DataService store.Service
|
||||
Admins []string
|
||||
AuthGoogle *auth.Provider
|
||||
AuthGithub *auth.Provider
|
||||
@@ -80,7 +80,7 @@ func (s *Server) Run() {
|
||||
rauth.Get("/user", s.userInfoCtrl)
|
||||
rauth.Put("/vote/{id}", s.voteCtrl)
|
||||
|
||||
s.mod = admin{dataStore: s.Store, exporter: s.Exporter, respCache: s.respCache}
|
||||
s.mod = admin{dataService: s.DataService, exporter: s.Exporter, respCache: s.respCache}
|
||||
rauth.Mount("/admin", s.mod.routes())
|
||||
})
|
||||
|
||||
@@ -140,7 +140,7 @@ func (s *Server) createCommentCtrl(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
id, err := s.Store.Create(comment)
|
||||
id, err := s.DataService.Create(comment)
|
||||
if err != nil {
|
||||
log.Printf("[WARN] can't save comment, %s", err)
|
||||
httpError(w, r, http.StatusInternalServerError, err, "can't save comment")
|
||||
@@ -160,7 +160,7 @@ func (s *Server) deleteCommentCtrl(w http.ResponseWriter, r *http.Request) {
|
||||
log.Printf("[DEBUG] delete comment %s", id)
|
||||
|
||||
url := r.URL.Query().Get("url")
|
||||
err := s.Store.Delete(store.Locator{URL: url}, id)
|
||||
err := s.DataService.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")
|
||||
@@ -185,7 +185,7 @@ func (s *Server) findCommentsCtrl(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
comments, err := s.Store.Find(store.Request{Locator: store.Locator{URL: url}, Sort: r.URL.Query().Get("sort")})
|
||||
comments, err := s.DataService.Find(store.Request{Locator: store.Locator{URL: url}, Sort: r.URL.Query().Get("sort")})
|
||||
if err != nil {
|
||||
log.Printf("[WARN] can't get comments for %s, %s", url, err)
|
||||
httpError(w, r, http.StatusInternalServerError, err, "can't load comments comment")
|
||||
@@ -216,7 +216,7 @@ func (s *Server) lastCommentsCtrl(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
comments, err := s.Store.Last(store.Locator{}, max)
|
||||
comments, err := s.DataService.Last(store.Locator{}, max)
|
||||
if err != nil {
|
||||
log.Printf("[WARN] can't get last comments, %s", err)
|
||||
httpError(w, r, http.StatusInternalServerError, err, "can't get last comments")
|
||||
@@ -236,7 +236,7 @@ func (s *Server) commentByIDCtrl(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
log.Printf("[DEBUG] get comments by id %s, %s", id, url)
|
||||
|
||||
comment, err := s.Store.Get(store.Locator{URL: url}, id)
|
||||
comment, err := s.DataService.GetByID(store.Locator{URL: url}, id)
|
||||
if err != nil {
|
||||
log.Printf("[WARN] can't get comment, %s", err)
|
||||
httpError(w, r, http.StatusInternalServerError, err, "can't get comment by id")
|
||||
@@ -260,7 +260,7 @@ func (s *Server) findUserCommentsCtrl(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
comments, err := s.Store.GetForUser(store.Locator{}, userID)
|
||||
comments, err := s.DataService.GetByUser(store.Locator{}, userID)
|
||||
if err != nil {
|
||||
log.Printf("[WARN] can't get comment, %s", err)
|
||||
httpError(w, r, http.StatusBadRequest, err, "can't get comment by user id")
|
||||
@@ -285,7 +285,7 @@ func (s *Server) userInfoCtrl(w http.ResponseWriter, r *http.Request) {
|
||||
// GET /count?url=post-url
|
||||
func (s *Server) countCtrl(w http.ResponseWriter, r *http.Request) {
|
||||
url := r.URL.Query().Get("url")
|
||||
count, err := s.Store.Count(store.Locator{URL: url})
|
||||
count, err := s.DataService.Count(store.Locator{URL: url})
|
||||
if err != nil {
|
||||
httpError(w, r, http.StatusBadRequest, err, "can't get count")
|
||||
return
|
||||
@@ -308,7 +308,7 @@ func (s *Server) voteCtrl(w http.ResponseWriter, r *http.Request) {
|
||||
url := r.URL.Query().Get("url")
|
||||
vote := r.URL.Query().Get("vote") == "1"
|
||||
|
||||
comment, err := s.Store.Vote(store.Locator{URL: url}, id, user.ID, vote)
|
||||
comment, err := s.DataService.Vote(store.Locator{URL: url}, id, user.ID, vote)
|
||||
if err != nil {
|
||||
log.Printf("[WARN] vote rejected for %s - %s, %s", user.ID, id, err)
|
||||
httpError(w, r, http.StatusBadRequest, err, "can't vote for comment")
|
||||
|
||||
+16
-47
@@ -178,8 +178,8 @@ func (b *BoltDB) Find(request Request) ([]Comment, error) {
|
||||
return res, err
|
||||
}
|
||||
|
||||
// Get comment by id across posts
|
||||
func (b *BoltDB) Get(locator Locator, commentID string) (comment Comment, err error) {
|
||||
// GetByID returns comment by id across posts
|
||||
func (b *BoltDB) GetByID(locator Locator, commentID string) (comment Comment, err error) {
|
||||
|
||||
err = b.View(func(tx *bolt.Tx) error {
|
||||
|
||||
@@ -262,29 +262,6 @@ func (b *BoltDB) Last(locator Locator, max int) (result []Comment, err error) {
|
||||
return result, err
|
||||
}
|
||||
|
||||
// Vote for comment by id and locator
|
||||
func (b *BoltDB) Vote(locator Locator, commentID string, userID string, val bool) (comment Comment, err error) {
|
||||
|
||||
comment, err = b.getComment(locator.URL, commentID)
|
||||
if err != nil {
|
||||
return comment, err
|
||||
}
|
||||
|
||||
if _, voted := comment.Votes[userID]; voted {
|
||||
return comment, errors.Errorf("user %s already voted for %s", userID, commentID)
|
||||
}
|
||||
// update votes and score
|
||||
comment.Votes[userID] = val
|
||||
|
||||
if val {
|
||||
comment.Score++
|
||||
} else {
|
||||
comment.Score--
|
||||
}
|
||||
|
||||
return comment, b.putComment(locator.URL, comment)
|
||||
}
|
||||
|
||||
// Count returns number of comments for locator
|
||||
func (b *BoltDB) Count(locator Locator) (count int, err error) {
|
||||
err = b.View(func(tx *bolt.Tx) error {
|
||||
@@ -348,19 +325,9 @@ func (b BoltDB) List(locator Locator) (result []string, err error) {
|
||||
return result, err
|
||||
}
|
||||
|
||||
// SetPin pin/un-pin comment as special
|
||||
func (b *BoltDB) SetPin(locator Locator, commentID string, status bool) error {
|
||||
comment, err := b.getComment(locator.URL, commentID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
comment.Pin = status
|
||||
return b.putComment(locator.URL, comment)
|
||||
}
|
||||
|
||||
// GetForUser extracts all comments for given site and given userID
|
||||
// GetByUser extracts all comments for given site and given userID
|
||||
// "users" bucket has sub-bucket for each userID, and keeps it as ts:ref
|
||||
func (b *BoltDB) GetForUser(locator Locator, userID string) (comments []Comment, err error) {
|
||||
func (b *BoltDB) GetByUser(locator Locator, userID string) (comments []Comment, err error) {
|
||||
|
||||
comments = []Comment{}
|
||||
commentRefs := []string{}
|
||||
@@ -397,7 +364,7 @@ func (b *BoltDB) GetForUser(locator Locator, userID string) (comments []Comment,
|
||||
if e != nil {
|
||||
return comments, errors.Wrapf(e, "can't parse reference %s", v)
|
||||
}
|
||||
if c, e := b.Get(Locator{URL: url, SiteID: locator.SiteID}, commentID); e == nil {
|
||||
if c, e := b.GetByID(Locator{URL: url, SiteID: locator.SiteID}, commentID); e == nil {
|
||||
comments = append(comments, c)
|
||||
}
|
||||
}
|
||||
@@ -405,18 +372,19 @@ func (b *BoltDB) GetForUser(locator Locator, userID string) (comments []Comment,
|
||||
return comments, err
|
||||
}
|
||||
|
||||
func (b *BoltDB) getComment(url string, commentID string) (comment Comment, err error) {
|
||||
// GetComment for locator.URL and commentID string
|
||||
func (b *BoltDB) GetComment(locator Locator, commentID string) (comment Comment, err error) {
|
||||
|
||||
err = b.View(func(tx *bolt.Tx) error {
|
||||
bucket := tx.Bucket([]byte(url))
|
||||
bucket := tx.Bucket([]byte(locator.URL))
|
||||
if bucket == nil {
|
||||
return errors.Errorf("no bucket %s in store", url)
|
||||
return errors.Errorf("no bucket %s in store", locator.URL)
|
||||
}
|
||||
|
||||
// get and unmarshal comment
|
||||
commentVal := bucket.Get([]byte(commentID))
|
||||
if commentVal == nil {
|
||||
return errors.Errorf("no comment for %s in store %s", commentID, url)
|
||||
return errors.Errorf("no comment for %s in store %s", commentID, locator.URL)
|
||||
}
|
||||
|
||||
if e := json.Unmarshal(commentVal, &comment); e != nil {
|
||||
@@ -427,9 +395,10 @@ func (b *BoltDB) getComment(url string, commentID string) (comment Comment, err
|
||||
return comment, err
|
||||
}
|
||||
|
||||
func (b *BoltDB) putComment(url string, comment Comment) error {
|
||||
// PutComment updates comment for locator.URL with mutable part of comment
|
||||
func (b *BoltDB) PutComment(locator Locator, comment Comment) error {
|
||||
|
||||
if curComment, err := b.getComment(url, comment.ID); err == nil {
|
||||
if curComment, err := b.GetComment(locator, comment.ID); err == nil {
|
||||
// preserve immutable fields
|
||||
comment.ParentID = curComment.ParentID
|
||||
comment.Locator = curComment.Locator
|
||||
@@ -438,9 +407,9 @@ func (b *BoltDB) putComment(url string, comment Comment) error {
|
||||
}
|
||||
|
||||
return b.Update(func(tx *bolt.Tx) error {
|
||||
bucket := tx.Bucket([]byte(url))
|
||||
bucket := tx.Bucket([]byte(locator.URL))
|
||||
if bucket == nil {
|
||||
return errors.Errorf("no bucket %s in store", url)
|
||||
return errors.Errorf("no bucket %s in store", locator.URL)
|
||||
}
|
||||
|
||||
// serialize comment to json []byte for bolt and save
|
||||
@@ -449,7 +418,7 @@ func (b *BoltDB) putComment(url string, comment Comment) error {
|
||||
return errors.Wrap(jerr, "can't marshal comment")
|
||||
}
|
||||
if err := bucket.Put([]byte(comment.ID), jdata); err != nil {
|
||||
return errors.Wrapf(err, "failed to put key %s to bucket %s", comment.ID, url)
|
||||
return errors.Wrapf(err, "failed to put key %s to bucket %s", comment.ID, locator.URL)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
+4
-53
@@ -45,7 +45,7 @@ func TestBoltDB_Delete(t *testing.T) {
|
||||
assert.Equal(t, 1, len(comments), "only 1 left in last")
|
||||
}
|
||||
|
||||
func TestBoltDB_Get(t *testing.T) {
|
||||
func TestBoltDB_GetByID(t *testing.T) {
|
||||
defer os.Remove(testDb)
|
||||
b := prep(t)
|
||||
|
||||
@@ -53,11 +53,11 @@ func TestBoltDB_Get(t *testing.T) {
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, 2, len(res))
|
||||
|
||||
comment, err := b.Get(Locator{URL: "https://radio-t.com"}, res[1].ID)
|
||||
comment, err := b.GetByID(Locator{URL: "https://radio-t.com"}, res[1].ID)
|
||||
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.GetByID(Locator{URL: "https://radio-t.com"}, "1234567")
|
||||
assert.NotNil(t, err)
|
||||
}
|
||||
|
||||
@@ -76,31 +76,6 @@ func TestBoltDB_Last(t *testing.T) {
|
||||
assert.Equal(t, "some text2", res[0].Text)
|
||||
}
|
||||
|
||||
func TestBoltDB_Vote(t *testing.T) {
|
||||
defer os.Remove(testDb)
|
||||
b := prep(t)
|
||||
|
||||
res, err := b.Last(Locator{URL: "https://radio-t.com"}, 0)
|
||||
t.Logf("%+v", res[0])
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, 2, len(res))
|
||||
assert.Equal(t, 0, res[0].Score)
|
||||
assert.Equal(t, map[string]bool{}, res[0].Votes)
|
||||
|
||||
c, err := b.Vote(Locator{URL: "https://radio-t.com"}, res[0].ID, "user1", true)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, 1, c.Score)
|
||||
assert.Equal(t, map[string]bool{"user1": true}, c.Votes)
|
||||
|
||||
_, err = b.Vote(Locator{URL: "https://radio-t.com"}, res[0].ID, "user1", true)
|
||||
assert.NotNil(t, err, "double-voting rejected")
|
||||
|
||||
res, err = b.Last(Locator{URL: "https://radio-t.com"}, 0)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, 2, len(res))
|
||||
assert.Equal(t, 1, res[0].Score)
|
||||
}
|
||||
|
||||
func TestBoltDB_Count(t *testing.T) {
|
||||
defer os.Remove(testDb)
|
||||
b := prep(t)
|
||||
@@ -141,35 +116,11 @@ func TestBoltDB_List(t *testing.T) {
|
||||
assert.Equal(t, []string{"https://radio-t.com", "https://radio-t.com/2"}, res)
|
||||
}
|
||||
|
||||
func TestBoltDB_Pin(t *testing.T) {
|
||||
defer os.Remove(testDb)
|
||||
b := prep(t)
|
||||
|
||||
res, err := b.Last(Locator{URL: "https://radio-t.com"}, 0)
|
||||
t.Logf("%+v", res[0])
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, 2, len(res))
|
||||
assert.Equal(t, false, res[0].Pin)
|
||||
|
||||
err = b.SetPin(Locator{URL: "https://radio-t.com"}, res[0].ID, true)
|
||||
assert.Nil(t, err)
|
||||
|
||||
c, err := b.Get(Locator{URL: "https://radio-t.com"}, res[0].ID)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, true, c.Pin)
|
||||
|
||||
err = b.SetPin(Locator{URL: "https://radio-t.com"}, res[0].ID, false)
|
||||
assert.Nil(t, err)
|
||||
c, err = b.Get(Locator{URL: "https://radio-t.com"}, res[0].ID)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, false, c.Pin)
|
||||
}
|
||||
|
||||
func TestBoltDB_GetForUser(t *testing.T) {
|
||||
defer os.Remove(testDb)
|
||||
b := prep(t)
|
||||
|
||||
res, err := b.GetForUser(Locator{SiteID: "radio-t"}, "user1")
|
||||
res, err := b.GetByUser(Locator{SiteID: "radio-t"}, "user1")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, 2, len(res))
|
||||
assert.Equal(t, "some text2", res[0].Text, "sorted by -time")
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
package store
|
||||
|
||||
import "github.com/pkg/errors"
|
||||
|
||||
// Service wraps store.Interface with additional methods
|
||||
type Service struct {
|
||||
Interface
|
||||
}
|
||||
|
||||
// SetPin pin/un-pin comment as special
|
||||
func (s *Service) SetPin(locator Locator, commentID string, status bool) error {
|
||||
comment, err := s.GetComment(locator, commentID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
comment.Pin = status
|
||||
return s.PutComment(locator, comment)
|
||||
}
|
||||
|
||||
// Vote for comment by id and locator
|
||||
func (s *Service) Vote(locator Locator, commentID string, userID string, val bool) (comment Comment, err error) {
|
||||
|
||||
comment, err = s.GetComment(locator, commentID)
|
||||
if err != nil {
|
||||
return comment, err
|
||||
}
|
||||
|
||||
if _, voted := comment.Votes[userID]; voted {
|
||||
return comment, errors.Errorf("user %s already voted for %s", userID, commentID)
|
||||
}
|
||||
// update votes and score
|
||||
comment.Votes[userID] = val
|
||||
|
||||
if val {
|
||||
comment.Score++
|
||||
} else {
|
||||
comment.Score--
|
||||
}
|
||||
|
||||
return comment, s.PutComment(locator, comment)
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package store
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestService_Vote(t *testing.T) {
|
||||
defer os.Remove(testDb)
|
||||
b := Service{Interface: prep(t)}
|
||||
|
||||
res, err := b.Last(Locator{URL: "https://radio-t.com"}, 0)
|
||||
t.Logf("%+v", res[0])
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, 2, len(res))
|
||||
assert.Equal(t, 0, res[0].Score)
|
||||
assert.Equal(t, map[string]bool{}, res[0].Votes)
|
||||
|
||||
c, err := b.Vote(Locator{URL: "https://radio-t.com"}, res[0].ID, "user1", true)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, 1, c.Score)
|
||||
assert.Equal(t, map[string]bool{"user1": true}, c.Votes)
|
||||
|
||||
_, err = b.Vote(Locator{URL: "https://radio-t.com"}, res[0].ID, "user1", true)
|
||||
assert.NotNil(t, err, "double-voting rejected")
|
||||
|
||||
res, err = b.Last(Locator{URL: "https://radio-t.com"}, 0)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, 2, len(res))
|
||||
assert.Equal(t, 1, res[0].Score)
|
||||
}
|
||||
|
||||
func TestBoltDB_Pin(t *testing.T) {
|
||||
defer os.Remove(testDb)
|
||||
b := Service{Interface: prep(t)}
|
||||
|
||||
res, err := b.Last(Locator{URL: "https://radio-t.com"}, 0)
|
||||
t.Logf("%+v", res[0])
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, 2, len(res))
|
||||
assert.Equal(t, false, res[0].Pin)
|
||||
|
||||
err = b.SetPin(Locator{URL: "https://radio-t.com"}, res[0].ID, true)
|
||||
assert.Nil(t, err)
|
||||
|
||||
c, err := b.GetByID(Locator{URL: "https://radio-t.com"}, res[0].ID)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, true, c.Pin)
|
||||
|
||||
err = b.SetPin(Locator{URL: "https://radio-t.com"}, res[0].ID, false)
|
||||
assert.Nil(t, err)
|
||||
c, err = b.GetByID(Locator{URL: "https://radio-t.com"}, res[0].ID)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, false, c.Pin)
|
||||
}
|
||||
+4
-4
@@ -54,18 +54,18 @@ type Request struct {
|
||||
// Interface defines basic CRUD for comments
|
||||
type Interface interface {
|
||||
Create(comment Comment) (commentID string, err error)
|
||||
GetComment(locator Locator, commentID string) (comment Comment, err error)
|
||||
PutComment(locator Locator, comment Comment) error
|
||||
Delete(locator Locator, commentID string) error
|
||||
Find(request Request) ([]Comment, error)
|
||||
Last(locator Locator, max int) ([]Comment, error)
|
||||
Get(locator Locator, commentID string) (Comment, error)
|
||||
Vote(locator Locator, commentID string, userID string, val bool) (Comment, error)
|
||||
GetByID(locator Locator, commentID string) (Comment, error)
|
||||
GetByUser(locator Locator, userID string) ([]Comment, error)
|
||||
Count(locator Locator) (int, error)
|
||||
List(locator Locator) ([]string, error)
|
||||
GetForUser(locator Locator, userID string) ([]Comment, error)
|
||||
|
||||
SetBlock(locator Locator, userID string, status bool) error
|
||||
IsBlocked(locator Locator, userID string) bool
|
||||
SetPin(locator Locator, commentID string, status bool) error
|
||||
}
|
||||
|
||||
func makeCommentID() string {
|
||||
|
||||
Reference in New Issue
Block a user