move comment alter functionality from rest and admin to store service
This commit is contained in:
@@ -26,7 +26,7 @@ func TestDisqus_Import(t *testing.T) {
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, 4, size)
|
||||
|
||||
last, err := dataStore.Last("test", 10, time.Time{})
|
||||
last, err := dataStore.Last("test", 10, time.Time{}, adminUser)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, 4, len(last), "4 comments imported")
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ type Exporter interface {
|
||||
// Store defines minimal interface needed to export and import comments
|
||||
type Store interface {
|
||||
Create(comment store.Comment) (commentID string, err error)
|
||||
Find(locator store.Locator, sort string) ([]store.Comment, error)
|
||||
Find(locator store.Locator, sort string, user store.User) ([]store.Comment, error)
|
||||
List(siteID string, limit int, skip int) ([]store.PostInfo, error)
|
||||
DeleteAll(siteID string) error
|
||||
Metas(siteID string) (umetas []service.UserMetaData, pmetas []service.PostMetaData, err error)
|
||||
@@ -42,6 +42,8 @@ type ImportParams struct {
|
||||
SiteID string
|
||||
}
|
||||
|
||||
var adminUser = store.User{Admin: true}
|
||||
|
||||
// ImportComments imports from given provider format and saves to store
|
||||
func ImportComments(p ImportParams) (int, error) {
|
||||
log.Printf("[INFO] import from %s (%s) to %s", p.InputFile, p.Provider, p.SiteID)
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/umputun/remark/backend/app/store"
|
||||
"github.com/umputun/remark/backend/app/store/admin"
|
||||
"github.com/umputun/remark/backend/app/store/engine"
|
||||
"github.com/umputun/remark/backend/app/store/service"
|
||||
@@ -36,7 +37,7 @@ func TestMigrator_ImportDisqus(t *testing.T) {
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, 4, size)
|
||||
|
||||
last, err := dataStore.Last("test", 10, time.Time{})
|
||||
last, err := dataStore.Last("test", 10, time.Time{}, store.User{})
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, 4, len(last), "4 comments imported")
|
||||
}
|
||||
@@ -62,7 +63,7 @@ func TestMigrator_ImportWordPress(t *testing.T) {
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, 3, size)
|
||||
|
||||
last, err := dataStore.Last("test", 10, time.Time{})
|
||||
last, err := dataStore.Last("test", 10, time.Time{}, store.User{})
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, 3, len(last), "3 comments imported")
|
||||
}
|
||||
@@ -92,7 +93,7 @@ func TestMigrator_ImportNative(t *testing.T) {
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, 2, size)
|
||||
|
||||
last, err := dataStore.Last("radio-t", 10, time.Time{})
|
||||
last, err := dataStore.Last("radio-t", 10, time.Time{}, store.User{})
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, 2, len(last), "2 comments imported")
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ func (n *Native) Export(w io.Writer, siteID string) (size int, err error) {
|
||||
commentsCount := 0
|
||||
for i := len(topics) - 1; i >= 0; i-- { // topics from List sorted in opposite direction
|
||||
topic := topics[i]
|
||||
comments, e := n.DataStore.Find(store.Locator{SiteID: siteID, URL: topic.URL}, "time")
|
||||
comments, e := n.DataStore.Find(store.Locator{SiteID: siteID, URL: topic.URL}, "time", adminUser)
|
||||
if e != nil {
|
||||
return commentsCount, e
|
||||
}
|
||||
|
||||
@@ -77,12 +77,13 @@ func TestNative_Import(t *testing.T) {
|
||||
{"id":"f863bd79-fec6-4a75-b308-61fe5dd02aa1","pid":"1234","text":"some text2","user":{"name":"user name","id":"user2","picture":"","ip":"293ec5b0cf154855258824ec7fac5dc63d176915","admin":false},"locator":{"site":"radio-t","url":"https://radio-t.com/2"},"score":0,"votes":{},"time":"2017-12-20T15:18:23-06:00"}`
|
||||
|
||||
b := prep(t) // write some recs
|
||||
r := Native{DataStore: &service.DataStore{Interface: b, AdminStore: admin.NewStaticStore("12345", []string{}, "")}}
|
||||
b.AdminStore = admin.NewStaticStore("12345", []string{}, "")
|
||||
r := Native{DataStore: b}
|
||||
size, err := r.Import(strings.NewReader(inp), "radio-t")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, 2, size)
|
||||
|
||||
comments, err := b.Last("radio-t", 10, time.Time{})
|
||||
comments, err := b.Last("radio-t", 10, time.Time{}, store.User{})
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, 2, len(comments))
|
||||
assert.Equal(t, "f863bd79-fec6-4a75-b308-61fe5dd02aa1", comments[0].ID)
|
||||
@@ -106,7 +107,8 @@ func TestNative_ImportWrongVersion(t *testing.T) {
|
||||
{"id":"f863bd79-fec6-4a75-b308-61fe5dd02aa1","pid":"1234","text":"some text2","user":{"name":"user name","id":"user2","picture":"","ip":"293ec5b0cf154855258824ec7fac5dc63d176915","admin":false},"locator":{"site":"radio-t","url":"https://radio-t.com/2"},"score":0,"votes":{},"time":"2017-12-20T15:18:23-06:00"}`
|
||||
|
||||
b := prep(t) // write some recs
|
||||
r := Native{DataStore: &service.DataStore{Interface: b, AdminStore: admin.NewStaticStore("12345", []string{}, "")}}
|
||||
b.AdminStore = admin.NewStaticStore("12345", []string{}, "")
|
||||
r := Native{DataStore: b}
|
||||
size, err := r.Import(strings.NewReader(inp), "radio-t")
|
||||
assert.EqualError(t, err, "unexpected import file version 2")
|
||||
assert.Equal(t, 0, size)
|
||||
@@ -126,11 +128,12 @@ func TestNative_ImportManyWithError(t *testing.T) {
|
||||
buf.WriteString("{}\n")
|
||||
|
||||
b := prep(t) // write some recs
|
||||
r := Native{DataStore: &service.DataStore{Interface: b, AdminStore: admin.NewStaticStore("12345", []string{}, "")}}
|
||||
b.AdminStore = admin.NewStaticStore("12345", []string{}, "")
|
||||
r := Native{DataStore: b}
|
||||
n, err := r.Import(buf, "radio-t")
|
||||
assert.EqualError(t, err, "failed to save 2 comments")
|
||||
assert.Equal(t, 1200, n)
|
||||
comments, err := b.Find(store.Locator{SiteID: "radio-t", URL: "https://radio-t.com"}, "time")
|
||||
comments, err := b.Find(store.Locator{SiteID: "radio-t", URL: "https://radio-t.com"}, "time", store.User{})
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, 1200, len(comments))
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ func TestWordPress_Import(t *testing.T) {
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, 3, size)
|
||||
|
||||
last, err := dataStore.Last(siteID, 10, time.Time{})
|
||||
last, err := dataStore.Last(siteID, 10, time.Time{}, adminUser)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, 3, len(last), "3 comments imported")
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ type Destination interface {
|
||||
|
||||
// Store defines the minimal interface accessing stored comments used by notifier
|
||||
type Store interface {
|
||||
Get(locator store.Locator, id string) (store.Comment, error)
|
||||
Get(locator store.Locator, id string, user store.User) (store.Comment, error)
|
||||
}
|
||||
|
||||
type request struct {
|
||||
@@ -69,7 +69,7 @@ func (s *Service) Submit(comment store.Comment) {
|
||||
}
|
||||
parentComment := store.Comment{}
|
||||
if s.dataService != nil {
|
||||
if p, err := s.dataService.Get(comment.Locator, comment.ParentID); err == nil {
|
||||
if p, err := s.dataService.Get(comment.Locator, comment.ParentID, store.User{}); err == nil {
|
||||
parentComment = p
|
||||
}
|
||||
}
|
||||
|
||||
@@ -146,7 +146,7 @@ func (m *mockDest) String() string { return fmt.Sprintf("mock id=%d, closed=%v",
|
||||
|
||||
type mockStore struct{ data map[string]store.Comment }
|
||||
|
||||
func (m *mockStore) Get(_ store.Locator, id string) (store.Comment, error) {
|
||||
func (m *mockStore) Get(_ store.Locator, id string, user store.User) (store.Comment, error) {
|
||||
res, ok := m.data[id]
|
||||
if !ok {
|
||||
return store.Comment{}, errors.New("no such id")
|
||||
|
||||
@@ -67,7 +67,7 @@ func (a *admin) getUserInfoCtrl(w http.ResponseWriter, r *http.Request) {
|
||||
siteID := r.URL.Query().Get("site")
|
||||
log.Printf("[INFO] get user info for %s, site %s", userID, siteID)
|
||||
|
||||
ucomments, err := a.dataService.User(siteID, userID, 1, 0)
|
||||
ucomments, err := a.dataService.User(siteID, userID, 1, 0, rest.GetUserOrEmpty(r))
|
||||
if err != nil || len(ucomments) == 0 {
|
||||
rest.SendErrorJSON(w, r, http.StatusBadRequest, err, "can't get user info", rest.ErrInternal)
|
||||
return
|
||||
@@ -222,38 +222,3 @@ func (a *admin) setPinCtrl(w http.ResponseWriter, r *http.Request) {
|
||||
func (a *admin) checkBlocked(siteID string, user store.User) bool {
|
||||
return a.dataService.IsBlocked(siteID, user.ID)
|
||||
}
|
||||
|
||||
// post-processes comments, hides text of all comments for blocked users,
|
||||
// resets score and votes too. Also hides sensitive info for non-admin users
|
||||
func (a *admin) alterComments(comments []store.Comment, r *http.Request) (res []store.Comment) {
|
||||
res = make([]store.Comment, len(comments))
|
||||
|
||||
user, err := rest.GetUserInfo(r)
|
||||
isAdmin := err == nil && user.Admin
|
||||
|
||||
for i, c := range comments {
|
||||
|
||||
blocked := a.dataService.IsBlocked(c.Locator.SiteID, c.User.ID)
|
||||
// process blocked users
|
||||
if blocked {
|
||||
if !isAdmin { // reset comment to deleted for non-admins
|
||||
c.SetDeleted(store.SoftDelete)
|
||||
}
|
||||
c.User.Blocked = true
|
||||
c.Deleted = true
|
||||
}
|
||||
|
||||
// set verified status retroactively
|
||||
if !blocked {
|
||||
c.User.Verified = a.dataService.IsVerified(c.Locator.SiteID, c.User.ID)
|
||||
}
|
||||
|
||||
// hide info from non-admins
|
||||
if !isAdmin {
|
||||
c.User.IP = ""
|
||||
}
|
||||
|
||||
res[i] = c
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
@@ -618,7 +618,7 @@ func TestAdmin_DeleteMeRequest(t *testing.T) {
|
||||
_, err = srv.DataService.Create(c2)
|
||||
assert.Nil(t, err)
|
||||
|
||||
comments, err := srv.DataService.User("radio-t", "user1", 0, 0)
|
||||
comments, err := srv.DataService.User("radio-t", "user1", 0, 0, store.User{})
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, 1, len(comments), "a comment for user1")
|
||||
|
||||
@@ -655,7 +655,7 @@ func TestAdmin_DeleteMeRequest(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, 200, resp.StatusCode)
|
||||
|
||||
_, err = srv.DataService.User("radio-t", "user1", 0, 0)
|
||||
_, err = srv.DataService.User("radio-t", "user1", 0, 0, store.User{})
|
||||
assert.EqualError(t, err, "no comments for user user1 in store")
|
||||
}
|
||||
|
||||
|
||||
@@ -307,41 +307,6 @@ func (s *Rest) routes() chi.Router {
|
||||
return router
|
||||
}
|
||||
|
||||
func (s *Rest) alterComments(comments []store.Comment, r *http.Request) (res []store.Comment) {
|
||||
|
||||
res = s.adminService.alterComments(comments, r) // apply admin's alteration
|
||||
|
||||
// prepare vote info for client view
|
||||
vote := func(c store.Comment, r *http.Request) store.Comment {
|
||||
|
||||
c.Vote = 0 // default is "none" (not voted)
|
||||
|
||||
user, err := rest.GetUserInfo(r)
|
||||
if err != nil {
|
||||
c.Votes = nil // hide voters list and don't set Vote for non-authed user
|
||||
return c
|
||||
}
|
||||
|
||||
if v, ok := c.Votes[user.ID]; ok {
|
||||
if v {
|
||||
c.Vote = 1
|
||||
} else {
|
||||
c.Vote = -1
|
||||
}
|
||||
}
|
||||
|
||||
c.Votes = nil // hide voters list
|
||||
return c
|
||||
}
|
||||
|
||||
for i, c := range res {
|
||||
c = vote(c, r)
|
||||
res[i] = c
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
// updateLimiter returns UpdateLimiter if set, or 10 if not
|
||||
func (s *Rest) updateLimiter() float64 {
|
||||
lmt := 10.0
|
||||
|
||||
@@ -67,7 +67,7 @@ func (s *Rest) createCommentCtrl(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
// DataService modifies comment
|
||||
finalComment, err := s.DataService.Get(comment.Locator, id)
|
||||
finalComment, err := s.DataService.Get(comment.Locator, id, rest.GetUserOrEmpty(r))
|
||||
if err != nil {
|
||||
rest.SendErrorJSON(w, r, http.StatusInternalServerError, err, "can't load created comment", rest.ErrInternal)
|
||||
return
|
||||
@@ -107,7 +107,7 @@ func (s *Rest) updateCommentCtrl(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
var currComment store.Comment
|
||||
var err error
|
||||
if currComment, err = s.DataService.Get(locator, id); err != nil {
|
||||
if currComment, err = s.DataService.Get(locator, id, rest.GetUserOrEmpty(r)); err != nil {
|
||||
rest.SendErrorJSON(w, r, http.StatusBadRequest, err, "can't find comment", rest.ErrCommentNotFound)
|
||||
return
|
||||
}
|
||||
@@ -213,7 +213,7 @@ func (s *Rest) userAllDataCtrl(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
// get comments in 100 in each paginated request
|
||||
for i := 0; i < 100; i++ {
|
||||
comments, errUser := s.DataService.User(siteID, user.ID, 100, i*100)
|
||||
comments, errUser := s.DataService.User(siteID, user.ID, 100, i*100, rest.GetUserOrEmpty(r))
|
||||
if errUser != nil {
|
||||
rest.SendErrorJSON(w, r, http.StatusInternalServerError, errUser, "can't get user comments", rest.ErrInternal)
|
||||
return
|
||||
|
||||
@@ -63,7 +63,7 @@ func TestRest_CreateOldPost(t *testing.T) {
|
||||
_, err := srv.DataService.Create(old)
|
||||
assert.Nil(t, err)
|
||||
|
||||
comments, err := srv.DataService.Find(store.Locator{SiteID: "radio-t", URL: "https://radio-t.com/blah1"}, "time")
|
||||
comments, err := srv.DataService.Find(store.Locator{SiteID: "radio-t", URL: "https://radio-t.com/blah1"}, "time", store.User{})
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, 1, len(comments))
|
||||
|
||||
|
||||
@@ -34,15 +34,14 @@ func (s *Rest) findCommentsCtrl(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
key := cache.NewKey(locator.SiteID).ID(URLKeyWithUser(r)).Scopes(locator.SiteID, locator.URL)
|
||||
data, err := s.Cache.Get(key, func() ([]byte, error) {
|
||||
comments, e := s.DataService.Find(locator, sort)
|
||||
comments, e := s.DataService.Find(locator, sort, rest.GetUserOrEmpty(r))
|
||||
if e != nil {
|
||||
comments = []store.Comment{} // error should clear comments and continue for post info
|
||||
}
|
||||
maskedComments := s.alterComments(comments, r)
|
||||
var b []byte
|
||||
switch r.URL.Query().Get("format") {
|
||||
case "tree":
|
||||
tree := service.MakeTree(maskedComments, sort, s.ReadOnlyAge)
|
||||
tree := service.MakeTree(comments, sort, s.ReadOnlyAge)
|
||||
if tree.Nodes == nil { // eliminate json nil serialization
|
||||
tree.Nodes = []*service.Node{}
|
||||
}
|
||||
@@ -51,7 +50,7 @@ func (s *Rest) findCommentsCtrl(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
b, e = encodeJSONWithHTML(tree)
|
||||
default:
|
||||
withInfo := commentsWithInfo{Comments: maskedComments}
|
||||
withInfo := commentsWithInfo{Comments: comments}
|
||||
if info, ee := s.DataService.Info(locator, s.ReadOnlyAge); ee == nil {
|
||||
withInfo.Info = info
|
||||
}
|
||||
@@ -132,9 +131,9 @@ func (s *Rest) lastCommentsCtrl(w http.ResponseWriter, r *http.Request) {
|
||||
sinceTime := time.Time{}
|
||||
since := r.URL.Query().Get("since")
|
||||
if since != "" {
|
||||
unixTS, err := strconv.ParseInt(since, 10, 64)
|
||||
if err != nil {
|
||||
rest.SendErrorJSON(w, r, http.StatusBadRequest, err, "can't translate since parameter", rest.ErrDecode)
|
||||
unixTS, e := strconv.ParseInt(since, 10, 64)
|
||||
if e != nil {
|
||||
rest.SendErrorJSON(w, r, http.StatusBadRequest, e, "can't translate since parameter", rest.ErrDecode)
|
||||
return
|
||||
}
|
||||
sinceTime = time.Unix(unixTS/1000, 1000000*(unixTS%1000)) // since param in msec timestamp
|
||||
@@ -142,11 +141,10 @@ func (s *Rest) lastCommentsCtrl(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
key := cache.NewKey(siteID).ID(URLKey(r)).Scopes(lastCommentsScope)
|
||||
data, err := s.Cache.Get(key, func() ([]byte, error) {
|
||||
comments, e := s.DataService.Last(siteID, limit, sinceTime)
|
||||
comments, e := s.DataService.Last(siteID, limit, sinceTime, rest.GetUserOrEmpty(r))
|
||||
if e != nil {
|
||||
return nil, e
|
||||
}
|
||||
comments = s.alterComments(comments, r)
|
||||
// filter deleted from last comments view. Blocked marked as deleted and will sneak in without
|
||||
filterDeleted := filterComments(comments, func(c store.Comment) bool { return !c.Deleted })
|
||||
return encodeJSONWithHTML(filterDeleted)
|
||||
@@ -171,12 +169,11 @@ func (s *Rest) commentByIDCtrl(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
log.Printf("[DEBUG] get comments by id %s, %s %s", id, siteID, url)
|
||||
|
||||
comment, err := s.DataService.Get(store.Locator{SiteID: siteID, URL: url}, id)
|
||||
comment, err := s.DataService.Get(store.Locator{SiteID: siteID, URL: url}, id, rest.GetUserOrEmpty(r))
|
||||
if err != nil {
|
||||
rest.SendErrorJSON(w, r, http.StatusBadRequest, err, "can't get comment by id", rest.ErrCommentNotFound)
|
||||
return
|
||||
}
|
||||
comment = s.alterComments([]store.Comment{comment}, r)[0]
|
||||
render.Status(r, http.StatusOK)
|
||||
|
||||
if err = R.RenderJSONWithHTML(w, r, comment); err != nil {
|
||||
@@ -204,11 +201,10 @@ func (s *Rest) findUserCommentsCtrl(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
key := cache.NewKey(siteID).ID(URLKeyWithUser(r)).Scopes(userID, siteID)
|
||||
data, err := s.Cache.Get(key, func() ([]byte, error) {
|
||||
comments, e := s.DataService.User(siteID, userID, limit, 0)
|
||||
comments, e := s.DataService.User(siteID, userID, limit, 0, rest.GetUserOrEmpty(r))
|
||||
if e != nil {
|
||||
return nil, e
|
||||
}
|
||||
comments = s.alterComments(comments, r)
|
||||
comments = filterComments(comments, func(c store.Comment) bool { return !c.Deleted })
|
||||
count, e := s.DataService.UserCount(siteID, userID)
|
||||
if e != nil {
|
||||
|
||||
@@ -28,11 +28,10 @@ func (s *Rest) rssPostCommentsCtrl(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
key := cache.NewKey(locator.SiteID).ID(URLKey(r)).Scopes(locator.SiteID, locator.URL)
|
||||
data, err := s.Cache.Get(key, func() ([]byte, error) {
|
||||
comments, e := s.DataService.Find(locator, "-time")
|
||||
comments, e := s.DataService.Find(locator, "-time", rest.GetUserOrEmpty(r))
|
||||
if e != nil {
|
||||
return nil, e
|
||||
}
|
||||
comments = s.alterComments(comments, r)
|
||||
rss, e := s.toRssFeed(locator.URL, comments, "post comments for "+r.URL.Query().Get("url"))
|
||||
if e != nil {
|
||||
return nil, e
|
||||
@@ -60,11 +59,10 @@ func (s *Rest) rssSiteCommentsCtrl(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
key := cache.NewKey(siteID).ID(URLKey(r)).Scopes(siteID, lastCommentsScope)
|
||||
data, err := s.Cache.Get(key, func() ([]byte, error) {
|
||||
comments, e := s.DataService.Last(siteID, maxRssItems, time.Time{})
|
||||
comments, e := s.DataService.Last(siteID, maxRssItems, time.Time{}, rest.GetUserOrEmpty(r))
|
||||
if e != nil {
|
||||
return nil, e
|
||||
}
|
||||
comments = s.alterComments(comments, r)
|
||||
|
||||
rss, e := s.toRssFeed(r.URL.Query().Get("site"), comments, "site comment for "+siteID)
|
||||
if e != nil {
|
||||
@@ -94,11 +92,10 @@ func (s *Rest) rssRepliesCtrl(w http.ResponseWriter, r *http.Request) {
|
||||
userName := ""
|
||||
key := cache.NewKey(siteID).ID(URLKey(r)).Scopes(siteID, lastCommentsScope)
|
||||
data, err := s.Cache.Get(key, func() (res []byte, e error) {
|
||||
comments, e := s.DataService.Last(siteID, maxLastCommentsReply, time.Time{})
|
||||
comments, e := s.DataService.Last(siteID, maxLastCommentsReply, time.Time{}, rest.GetUserOrEmpty(r))
|
||||
if e != nil {
|
||||
return nil, errors.Wrap(e, "can't get last comments")
|
||||
}
|
||||
comments = s.alterComments(comments, r)
|
||||
replies := []store.Comment{}
|
||||
for _, c := range comments {
|
||||
if len(replies) > maxRssItems || c.Timestamp.Add(maxReplyDuration).Before(time.Now()) {
|
||||
@@ -109,7 +106,7 @@ func (s *Rest) rssRepliesCtrl(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
if c.ParentID != "" && !c.Deleted && c.User.ID != userID { // not interested in replies to yourself
|
||||
var pc store.Comment
|
||||
if pc, e = s.DataService.Get(c.Locator, c.ParentID); e != nil {
|
||||
if pc, e = s.DataService.Get(c.Locator, c.ParentID, rest.GetUserOrEmpty(r)); e != nil {
|
||||
return nil, errors.Wrap(e, "can't get parent comment")
|
||||
}
|
||||
if pc.User.ID == userID {
|
||||
@@ -166,7 +163,7 @@ func (s *Rest) toRssFeed(url string, comments []store.Comment, description strin
|
||||
}
|
||||
if c.ParentID != "" {
|
||||
// add indication to parent comment
|
||||
parentComment, err := s.DataService.Get(c.Locator, c.ParentID)
|
||||
parentComment, err := s.DataService.Get(c.Locator, c.ParentID, store.User{})
|
||||
if err == nil {
|
||||
f.Title = fmt.Sprintf("%s > %s", c.User.Name, parentComment.User.Name)
|
||||
} else {
|
||||
|
||||
@@ -36,7 +36,15 @@ func GetUserInfo(r *http.Request) (user store.User, err error) {
|
||||
Verified: u.BoolAttr("verified"),
|
||||
Blocked: u.BoolAttr("blocked"),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// GetUserOrEmpty attempts to get user info from request and returns empty object if failed
|
||||
func GetUserOrEmpty(r *http.Request) store.User {
|
||||
user, err := GetUserInfo(r)
|
||||
if err != nil {
|
||||
return store.User{}
|
||||
}
|
||||
return user
|
||||
}
|
||||
|
||||
// SetUserInfo sets user into request context
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
"github.com/umputun/remark/backend/app/store"
|
||||
)
|
||||
|
||||
//go:generate sh -c "mockery -inpkg -name Interface -print > file.tmp && mv file.tmp engine_mock.go"
|
||||
//go:generate sh -c "mockery -inpkg -name Interface -print > /tmp/engine-mock.tmp && mv /tmp/engine-mock.tmp engine_mock.go"
|
||||
|
||||
// Interface combines all store interfaces
|
||||
type Interface interface {
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// Package service wraps engine interfaces with common logic unrelated to any particular engine implementation.
|
||||
// All consumers should be using service.DataStore and not the naked engine!
|
||||
|
||||
package service
|
||||
|
||||
import (
|
||||
@@ -96,12 +99,48 @@ func (s *DataStore) Create(comment store.Comment) (commentID string, err error)
|
||||
return s.Interface.Create(comment)
|
||||
}
|
||||
|
||||
// Find wraps engine's Find call and alter results if needed
|
||||
func (s *DataStore) Find(locator store.Locator, sort string, user store.User) ([]store.Comment, error) {
|
||||
comments, err := s.Interface.Find(locator, sort)
|
||||
if err != nil {
|
||||
return comments, err
|
||||
}
|
||||
|
||||
changedSort := false
|
||||
// set votes controversy for comments added prior to #274
|
||||
for i, c := range comments {
|
||||
if c.Controversy == 0 && len(c.Votes) > 0 {
|
||||
c.Controversy = s.controversy(s.upsAndDowns(c))
|
||||
if !changedSort && strings.Contains(sort, "controversy") { // trigger sort change
|
||||
changedSort = true
|
||||
}
|
||||
}
|
||||
comments[i] = s.alterComment(c, user)
|
||||
}
|
||||
|
||||
// resort commits if altered
|
||||
if changedSort {
|
||||
comments = engine.SortComments(comments, sort)
|
||||
}
|
||||
|
||||
return comments, nil
|
||||
}
|
||||
|
||||
// Get comment by ID
|
||||
func (s *DataStore) Get(locator store.Locator, commentID string, user store.User) (store.Comment, error) {
|
||||
c, err := s.Interface.Get(locator, commentID)
|
||||
if err != nil {
|
||||
return store.Comment{}, err
|
||||
}
|
||||
return s.alterComment(c, user), nil
|
||||
}
|
||||
|
||||
// submitImages initiated delayed commit of all images from the comment uploaded to remark42
|
||||
func (s *DataStore) submitImages(comment store.Comment) {
|
||||
|
||||
s.ImageService.Submit(func() []string {
|
||||
c := comment
|
||||
cc, err := s.Get(c.Locator, c.ID) // this can be called after last edit, we have to retrieve fresh comment
|
||||
cc, err := s.Interface.Get(c.Locator, c.ID) // this can be called after last edit, we have to retrieve fresh comment
|
||||
if err != nil {
|
||||
log.Printf("[WARN] can't get comment's %s text for image extraction, %v", c.ID, err)
|
||||
return nil
|
||||
@@ -143,7 +182,7 @@ func (s *DataStore) prepareNewComment(comment store.Comment) (store.Comment, err
|
||||
|
||||
// SetPin pin/un-pin comment as special
|
||||
func (s *DataStore) SetPin(locator store.Locator, commentID string, status bool) error {
|
||||
comment, err := s.Get(locator, commentID)
|
||||
comment, err := s.Interface.Get(locator, commentID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -158,7 +197,7 @@ func (s *DataStore) Vote(locator store.Locator, commentID string, userID string,
|
||||
cLock.Lock() // prevents race on voting
|
||||
defer cLock.Unlock()
|
||||
|
||||
comment, err = s.Get(locator, commentID)
|
||||
comment, err = s.Interface.Get(locator, commentID)
|
||||
if err != nil {
|
||||
return comment, err
|
||||
}
|
||||
@@ -246,7 +285,7 @@ type EditRequest struct {
|
||||
|
||||
// EditComment to edit text and update Edit info
|
||||
func (s *DataStore) EditComment(locator store.Locator, commentID string, req EditRequest) (comment store.Comment, err error) {
|
||||
comment, err = s.Get(locator, commentID)
|
||||
comment, err = s.Interface.Get(locator, commentID)
|
||||
if err != nil {
|
||||
return comment, err
|
||||
}
|
||||
@@ -295,7 +334,7 @@ func (s *DataStore) HasReplies(comment store.Comment) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
comments, err := s.Last(comment.Locator.SiteID, maxLastCommentsReply, time.Time{})
|
||||
comments, err := s.Interface.Last(comment.Locator.SiteID, maxLastCommentsReply, time.Time{})
|
||||
if err != nil {
|
||||
log.Printf("[WARN] can't get last comments for reply check, %v", err)
|
||||
return false
|
||||
@@ -318,7 +357,7 @@ func (s *DataStore) SetTitle(locator store.Locator, commentID string) (comment s
|
||||
return comment, errors.New("no title extractor")
|
||||
}
|
||||
|
||||
comment, err = s.Get(locator, commentID)
|
||||
comment, err = s.Interface.Get(locator, commentID)
|
||||
if err != nil {
|
||||
return comment, err
|
||||
}
|
||||
@@ -452,30 +491,22 @@ func (s *DataStore) SetMetas(siteID string, umetas []UserMetaData, pmetas []Post
|
||||
return errs.ErrorOrNil()
|
||||
}
|
||||
|
||||
// Find wraps engine's Find call and alter results if needed
|
||||
func (s *DataStore) Find(locator store.Locator, sort string) ([]store.Comment, error) {
|
||||
comments, err := s.Interface.Find(locator, sort)
|
||||
// User gets comment for given userID on siteID
|
||||
func (s *DataStore) User(siteID, userID string, limit, skip int, user store.User) ([]store.Comment, error) {
|
||||
comments, err := s.Interface.User(siteID, userID, limit, skip)
|
||||
if err != nil {
|
||||
return comments, err
|
||||
}
|
||||
return s.alterComments(comments, user), nil
|
||||
}
|
||||
|
||||
changedSort := false
|
||||
// set votes controversy for comments added prior to #274
|
||||
for i, c := range comments {
|
||||
if c.Controversy == 0 && len(c.Votes) > 0 {
|
||||
comments[i].Controversy = s.controversy(s.upsAndDowns(c))
|
||||
if !changedSort && strings.Contains(sort, "controversy") { // trigger sort change
|
||||
changedSort = true
|
||||
}
|
||||
}
|
||||
// Last gets last comments for site, cross-post. Limited by count and optional since ts
|
||||
func (s *DataStore) Last(siteID string, limit int, since time.Time, user store.User) ([]store.Comment, error) {
|
||||
comments, err := s.Interface.Last(siteID, limit, since)
|
||||
if err != nil {
|
||||
return comments, err
|
||||
}
|
||||
|
||||
// resort commits if altered
|
||||
if changedSort {
|
||||
comments = engine.SortComments(comments, sort)
|
||||
}
|
||||
|
||||
return comments, nil
|
||||
return s.alterComments(comments, user), nil
|
||||
}
|
||||
|
||||
func (s *DataStore) upsAndDowns(c store.Comment) (ups, downs int) {
|
||||
@@ -503,3 +534,54 @@ func (s *DataStore) getScopedLocks(id string) (lock sync.Locker) {
|
||||
|
||||
return lock
|
||||
}
|
||||
|
||||
func (s *DataStore) alterComments(cc []store.Comment, user store.User) (res []store.Comment) {
|
||||
res = make([]store.Comment, len(cc))
|
||||
for i, c := range cc {
|
||||
res[i] = s.alterComment(c, user)
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
func (s *DataStore) alterComment(c store.Comment, user store.User) (res store.Comment) {
|
||||
|
||||
blocked := s.IsBlocked(c.Locator.SiteID, c.User.ID)
|
||||
// process blocked users
|
||||
if blocked {
|
||||
if !user.Admin { // reset comment to deleted for non-admins
|
||||
c.SetDeleted(store.SoftDelete)
|
||||
}
|
||||
c.User.Blocked = true
|
||||
c.Deleted = true
|
||||
}
|
||||
|
||||
// set verified status retroactively
|
||||
if !blocked {
|
||||
c.User.Verified = s.IsVerified(c.Locator.SiteID, c.User.ID)
|
||||
}
|
||||
|
||||
// hide info from non-admins
|
||||
if !user.Admin {
|
||||
c.User.IP = ""
|
||||
}
|
||||
|
||||
c = s.prepVotes(c, user)
|
||||
return c
|
||||
}
|
||||
|
||||
// prepare vote info for client view
|
||||
func (s *DataStore) prepVotes(c store.Comment, user store.User) store.Comment {
|
||||
|
||||
c.Vote = 0 // default is "none" (not voted)
|
||||
|
||||
if v, ok := c.Votes[user.ID]; ok {
|
||||
if v {
|
||||
c.Vote = 1
|
||||
} else {
|
||||
c.Vote = -1
|
||||
}
|
||||
}
|
||||
|
||||
c.Votes = nil // hide voters list
|
||||
return c
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
@@ -18,11 +19,11 @@ import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/umputun/remark/backend/app/store/image"
|
||||
|
||||
"github.com/umputun/remark/backend/app/store"
|
||||
"github.com/umputun/remark/backend/app/store/admin"
|
||||
"github.com/umputun/remark/backend/app/store/engine"
|
||||
"github.com/umputun/remark/backend/app/store/image"
|
||||
)
|
||||
|
||||
var testDb = "/tmp/test-remark.db"
|
||||
@@ -40,7 +41,7 @@ func TestService_CreateFromEmpty(t *testing.T) {
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, id != "", id)
|
||||
|
||||
res, err := b.Get(store.Locator{URL: "https://radio-t.com", SiteID: "radio-t"}, id)
|
||||
res, err := b.Interface.Get(store.Locator{URL: "https://radio-t.com", SiteID: "radio-t"}, id)
|
||||
assert.NoError(t, err)
|
||||
t.Logf("%+v", res)
|
||||
assert.Equal(t, "text", res.Text)
|
||||
@@ -66,7 +67,7 @@ func TestService_CreateFromPartial(t *testing.T) {
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, id != "", id)
|
||||
|
||||
res, err := b.Get(store.Locator{URL: "https://radio-t.com", SiteID: "radio-t"}, id)
|
||||
res, err := b.Interface.Get(store.Locator{URL: "https://radio-t.com", SiteID: "radio-t"}, id)
|
||||
assert.NoError(t, err)
|
||||
t.Logf("%+v", res)
|
||||
assert.Equal(t, "text", res.Text)
|
||||
@@ -94,7 +95,7 @@ func TestService_CreateFromPartialWithTitle(t *testing.T) {
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, id != "", id)
|
||||
|
||||
res, err := b.Get(store.Locator{URL: "https://radio-t.com/p/2018/12/29/podcast-630/", SiteID: "radio-t"}, id)
|
||||
res, err := b.Interface.Get(store.Locator{URL: "https://radio-t.com/p/2018/12/29/podcast-630/", SiteID: "radio-t"}, id)
|
||||
assert.NoError(t, err)
|
||||
t.Logf("%+v", res)
|
||||
assert.Equal(t, "Радио-Т 630 — Радио-Т Подкаст", res.PostTitle)
|
||||
@@ -102,7 +103,7 @@ func TestService_CreateFromPartialWithTitle(t *testing.T) {
|
||||
comment.PostTitle = "post blah"
|
||||
id, err = b.Create(comment)
|
||||
assert.NoError(t, err)
|
||||
res, err = b.Get(store.Locator{URL: "https://radio-t.com/p/2018/12/29/podcast-630/", SiteID: "radio-t"}, id)
|
||||
res, err = b.Interface.Get(store.Locator{URL: "https://radio-t.com/p/2018/12/29/podcast-630/", SiteID: "radio-t"}, id)
|
||||
assert.NoError(t, err)
|
||||
t.Logf("%+v", res)
|
||||
assert.Equal(t, "post blah", res.PostTitle, "keep comment title")
|
||||
@@ -145,7 +146,7 @@ func TestService_SetTitle(t *testing.T) {
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, id != "", id)
|
||||
|
||||
res, err := b.Get(store.Locator{URL: tss.URL + "/post1", SiteID: "radio-t"}, id)
|
||||
res, err := b.Interface.Get(store.Locator{URL: tss.URL + "/post1", SiteID: "radio-t"}, id)
|
||||
assert.NoError(t, err)
|
||||
t.Logf("%+v", res)
|
||||
assert.Equal(t, "", res.PostTitle)
|
||||
@@ -174,7 +175,7 @@ func TestService_Vote(t *testing.T) {
|
||||
_, err := b.Create(comment)
|
||||
assert.NoError(t, err)
|
||||
|
||||
res, err := b.Last("radio-t", 0, time.Time{})
|
||||
res, err := b.Interface.Last("radio-t", 0, time.Time{})
|
||||
t.Logf("%+v", res[0])
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, 3, len(res))
|
||||
@@ -195,7 +196,7 @@ func TestService_Vote(t *testing.T) {
|
||||
assert.NotNil(t, err, "double-voting rejected")
|
||||
assert.True(t, strings.HasPrefix(err.Error(), "user user1 already voted"))
|
||||
|
||||
res, err = b.Last("radio-t", 0, time.Time{})
|
||||
res, err = b.Interface.Last("radio-t", 0, time.Time{})
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, 3, len(res))
|
||||
assert.Equal(t, 1, res[0].Score)
|
||||
@@ -204,7 +205,7 @@ func TestService_Vote(t *testing.T) {
|
||||
|
||||
_, err = b.Vote(store.Locator{URL: "https://radio-t.com", SiteID: "radio-t"}, res[0].ID, "user1", false)
|
||||
assert.Nil(t, err, "vote reset")
|
||||
res, err = b.Last("radio-t", 0, time.Time{})
|
||||
res, err = b.Interface.Last("radio-t", 0, time.Time{})
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, 3, len(res))
|
||||
assert.Equal(t, 0, res[0].Score)
|
||||
@@ -250,7 +251,7 @@ func TestService_VoteAggressive(t *testing.T) {
|
||||
_, err := b.Create(comment)
|
||||
assert.NoError(t, err)
|
||||
|
||||
res, err := b.Last("radio-t", 0, time.Time{})
|
||||
res, err := b.Interface.Last("radio-t", 0, time.Time{})
|
||||
require.Nil(t, err)
|
||||
t.Logf("%+v", res[0])
|
||||
assert.Equal(t, 3, len(res))
|
||||
@@ -271,7 +272,7 @@ func TestService_VoteAggressive(t *testing.T) {
|
||||
}()
|
||||
}
|
||||
wg.Wait()
|
||||
res, err = b.Last("radio-t", 0, time.Time{})
|
||||
res, err = b.Interface.Last("radio-t", 0, time.Time{})
|
||||
require.NoError(t, err)
|
||||
|
||||
t.Logf("%+v", res[0])
|
||||
@@ -290,7 +291,7 @@ func TestService_VoteAggressive(t *testing.T) {
|
||||
}()
|
||||
}
|
||||
wg.Wait()
|
||||
res, err = b.Last("radio-t", 0, time.Time{})
|
||||
res, err = b.Interface.Last("radio-t", 0, time.Time{})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, 3, len(res))
|
||||
t.Logf("%+v %d", res[0], res[0].Score)
|
||||
@@ -309,7 +310,7 @@ func TestService_VoteConcurrent(t *testing.T) {
|
||||
}
|
||||
_, err := b.Create(comment)
|
||||
assert.NoError(t, err)
|
||||
res, err := b.Last("radio-t", 0, time.Time{})
|
||||
res, err := b.Interface.Last("radio-t", 0, time.Time{})
|
||||
require.Nil(t, err)
|
||||
|
||||
// concurrent vote +1 as multiple users for the same comment
|
||||
@@ -324,7 +325,7 @@ func TestService_VoteConcurrent(t *testing.T) {
|
||||
}()
|
||||
}
|
||||
wg.Wait()
|
||||
res, err = b.Last("radio-t", 0, time.Time{})
|
||||
res, err = b.Interface.Last("radio-t", 0, time.Time{})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, 100, res[0].Score, "should have 100 score")
|
||||
assert.Equal(t, 100, len(res[0].Votes), "should have 100 votes")
|
||||
@@ -370,7 +371,7 @@ func TestService_VoteControversy(t *testing.T) {
|
||||
assert.InDelta(t, 1.73, c.Controversy, 0.01)
|
||||
|
||||
// check if stored
|
||||
res, err := b.Last("radio-t", 0, time.Time{})
|
||||
res, err := b.Interface.Last("radio-t", 0, time.Time{})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, 1, res[0].Score, "should have 1 score")
|
||||
assert.InDelta(t, 1.73, res[0].Controversy, 0.01)
|
||||
@@ -404,7 +405,7 @@ func TestService_Pin(t *testing.T) {
|
||||
defer teardown(t)
|
||||
b := DataStore{Interface: prepStoreEngine(t), AdminStore: admin.NewStaticKeyStore("secret 123")}
|
||||
|
||||
res, err := b.Last("radio-t", 0, time.Time{})
|
||||
res, err := b.Interface.Last("radio-t", 0, time.Time{})
|
||||
t.Logf("%+v", res[0])
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, 2, len(res))
|
||||
@@ -413,13 +414,13 @@ func TestService_Pin(t *testing.T) {
|
||||
err = b.SetPin(store.Locator{URL: "https://radio-t.com", SiteID: "radio-t"}, res[0].ID, true)
|
||||
assert.Nil(t, err)
|
||||
|
||||
c, err := b.Get(store.Locator{URL: "https://radio-t.com", SiteID: "radio-t"}, res[0].ID)
|
||||
c, err := b.Interface.Get(store.Locator{URL: "https://radio-t.com", SiteID: "radio-t"}, res[0].ID)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, true, c.Pin)
|
||||
|
||||
err = b.SetPin(store.Locator{URL: "https://radio-t.com", SiteID: "radio-t"}, res[0].ID, false)
|
||||
assert.Nil(t, err)
|
||||
c, err = b.Get(store.Locator{URL: "https://radio-t.com", SiteID: "radio-t"}, res[0].ID)
|
||||
c, err = b.Interface.Get(store.Locator{URL: "https://radio-t.com", SiteID: "radio-t"}, res[0].ID)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, false, c.Pin)
|
||||
}
|
||||
@@ -428,7 +429,7 @@ func TestService_EditComment(t *testing.T) {
|
||||
defer teardown(t)
|
||||
b := DataStore{Interface: prepStoreEngine(t), AdminStore: admin.NewStaticKeyStore("secret 123")}
|
||||
|
||||
res, err := b.Last("radio-t", 0, time.Time{})
|
||||
res, err := b.Interface.Last("radio-t", 0, time.Time{})
|
||||
t.Logf("%+v", res[0])
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, 2, len(res))
|
||||
@@ -441,7 +442,7 @@ func TestService_EditComment(t *testing.T) {
|
||||
assert.Equal(t, "xxx", comment.Text)
|
||||
assert.Equal(t, "yyy", comment.Orig)
|
||||
|
||||
c, err := b.Get(store.Locator{URL: "https://radio-t.com", SiteID: "radio-t"}, res[0].ID)
|
||||
c, err := b.Interface.Get(store.Locator{URL: "https://radio-t.com", SiteID: "radio-t"}, res[0].ID)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, "my edit", c.Edit.Summary)
|
||||
assert.Equal(t, "xxx", c.Text)
|
||||
@@ -455,7 +456,7 @@ func TestService_DeleteComment(t *testing.T) {
|
||||
defer teardown(t)
|
||||
b := DataStore{Interface: prepStoreEngine(t), AdminStore: admin.NewStaticKeyStore("secret 123")}
|
||||
|
||||
res, err := b.Last("radio-t", 0, time.Time{})
|
||||
res, err := b.Interface.Last("radio-t", 0, time.Time{})
|
||||
t.Logf("%+v", res[0])
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, 2, len(res))
|
||||
@@ -464,7 +465,7 @@ func TestService_DeleteComment(t *testing.T) {
|
||||
_, err = b.EditComment(store.Locator{URL: "https://radio-t.com", SiteID: "radio-t"}, res[0].ID, EditRequest{Delete: true})
|
||||
assert.Nil(t, err)
|
||||
|
||||
c, err := b.Get(store.Locator{URL: "https://radio-t.com", SiteID: "radio-t"}, res[0].ID)
|
||||
c, err := b.Interface.Get(store.Locator{URL: "https://radio-t.com", SiteID: "radio-t"}, res[0].ID)
|
||||
assert.Nil(t, err)
|
||||
assert.True(t, c.Deleted)
|
||||
t.Logf("%+v", c)
|
||||
@@ -474,7 +475,7 @@ func TestService_EditCommentDurationFailed(t *testing.T) {
|
||||
defer teardown(t)
|
||||
b := DataStore{Interface: prepStoreEngine(t), EditDuration: 100 * time.Millisecond, AdminStore: admin.NewStaticKeyStore("secret 123")}
|
||||
|
||||
res, err := b.Last("radio-t", 0, time.Time{})
|
||||
res, err := b.Interface.Last("radio-t", 0, time.Time{})
|
||||
t.Logf("%+v", res[0])
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, 2, len(res))
|
||||
@@ -491,7 +492,7 @@ func TestService_EditCommentReplyFailed(t *testing.T) {
|
||||
defer teardown(t)
|
||||
b := DataStore{Interface: prepStoreEngine(t), AdminStore: admin.NewStaticKeyStore("secret 123")}
|
||||
|
||||
res, err := b.Last("radio-t", 0, time.Time{})
|
||||
res, err := b.Interface.Last("radio-t", 0, time.Time{})
|
||||
t.Logf("%+v", res[1])
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, 2, len(res))
|
||||
@@ -534,6 +535,7 @@ func TestService_ValidateComment(t *testing.T) {
|
||||
assert.Nil(t, e, "check #%d", n)
|
||||
continue
|
||||
}
|
||||
require.NotNil(t, e)
|
||||
assert.EqualError(t, tt.err, e.Error(), "check #%d", n)
|
||||
}
|
||||
}
|
||||
@@ -669,7 +671,7 @@ func TestService_Find(t *testing.T) {
|
||||
b := DataStore{Interface: prepStoreEngine(t), EditDuration: 100 * time.Millisecond,
|
||||
AdminStore: admin.NewStaticStore("secret 123", []string{"user2"}, "user@email.com")}
|
||||
|
||||
res, err := b.Find(store.Locator{URL: "https://radio-t.com", SiteID: "radio-t"}, "time")
|
||||
res, err := b.Find(store.Locator{URL: "https://radio-t.com", SiteID: "radio-t"}, "time", store.User{})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, 2, len(res))
|
||||
|
||||
@@ -687,7 +689,7 @@ func TestService_Find(t *testing.T) {
|
||||
assert.Nil(t, err)
|
||||
|
||||
// make sure Controversy altered
|
||||
res, err = b.Find(store.Locator{URL: "https://radio-t.com", SiteID: "radio-t"}, "-controversy")
|
||||
res, err = b.Find(store.Locator{URL: "https://radio-t.com", SiteID: "radio-t"}, "-controversy", store.User{})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, 3, len(res))
|
||||
assert.Equal(t, "123456", res[0].ID)
|
||||
@@ -722,6 +724,26 @@ func TestService_submitImages(t *testing.T) {
|
||||
time.Sleep(250 * time.Millisecond)
|
||||
}
|
||||
|
||||
func TestService_alterComment(t *testing.T) {
|
||||
defer teardown(t)
|
||||
svc := DataStore{Interface: prepStoreEngine(t), AdminStore: admin.NewStaticKeyStore("secret 123")}
|
||||
|
||||
tbl := []struct {
|
||||
c store.Comment
|
||||
u store.User
|
||||
r store.Comment
|
||||
}{
|
||||
{store.Comment{}, store.User{}, store.Comment{}},
|
||||
{store.Comment{}, store.User{}, store.Comment{}},
|
||||
}
|
||||
for i, tt := range tbl {
|
||||
t.Run(strconv.Itoa(i), func(t *testing.T) {
|
||||
r := svc.alterComment(tt.c, tt.u)
|
||||
assert.Equal(t, tt.r, r)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// makes new boltdb, put two records
|
||||
func prepStoreEngine(t *testing.T) engine.Interface {
|
||||
_ = os.Remove(testDb)
|
||||
|
||||
+1
-2
@@ -24,8 +24,7 @@ require (
|
||||
github.com/golang/protobuf v1.3.1 // indirect
|
||||
github.com/google/uuid v0.0.0-20161128191214-064e2069ce9c
|
||||
github.com/gorilla/feeds v1.1.0
|
||||
github.com/hashicorp/errwrap v1.0.0 // indirect
|
||||
github.com/hashicorp/go-multierror v0.0.0-20171204182908-b7773ae21874
|
||||
github.com/hashicorp/go-multierror v1.0.0
|
||||
github.com/hashicorp/golang-lru v0.5.1 // indirect
|
||||
github.com/jessevdk/go-flags v0.0.0-20180331124232-1c38ed7ad0cc
|
||||
github.com/microcosm-cc/bluemonday v0.0.0-20171222152607-542fd4642604
|
||||
|
||||
@@ -71,6 +71,8 @@ github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/U
|
||||
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
github.com/hashicorp/go-multierror v0.0.0-20171204182908-b7773ae21874 h1:em+tTnzgU7N22woTBMcSJAOW7tRHAkK597W+MD/CpK8=
|
||||
github.com/hashicorp/go-multierror v0.0.0-20171204182908-b7773ae21874/go.mod h1:JMRHfdO9jKNzS/+BTlxCjKNQHg/jZAft8U7LloJvN7I=
|
||||
github.com/hashicorp/go-multierror v1.0.0 h1:iVjPR7a6H0tWELX5NxNe7bYopibicUzc7uPribsnS6o=
|
||||
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
|
||||
github.com/hashicorp/golang-lru v0.5.0 h1:CL2msUPvZTLb5O648aiLNJw3hnBxN2+1Jq8rCOH9wdo=
|
||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU=
|
||||
@@ -107,6 +109,7 @@ github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48=
|
||||
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
|
||||
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/umputun/remark v1.3.2 h1:m0PvvY7GEWSIjfQeqddvglJVswxUoSBPi4RrsI3sJz8=
|
||||
go.etcd.io/bbolt v1.3.2 h1:Z/90sZLPOeCy2PwprqkFa25PdkusRzaj9P8zm/KNyvk=
|
||||
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||
|
||||
+1
@@ -1,5 +1,6 @@
|
||||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/globalsign/mgo v0.0.0-20180615134936-113d3961e731 h1:y7wyeiA6T+TT+HGC9DYypvLkUeg99N4rqHMzn2MmjYk=
|
||||
github.com/globalsign/mgo v0.0.0-20180615134936-113d3961e731/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
|
||||
|
||||
+2
@@ -1 +1,3 @@
|
||||
module github.com/hashicorp/golang-lru
|
||||
|
||||
go 1.12
|
||||
|
||||
Reference in New Issue
Block a user