move reply retrieval to service, fix incorrect RSS title for reply

This commit is contained in:
Umputun
2019-05-19 12:56:47 -05:00
parent 6de89888c3
commit 350cca894d
4 changed files with 143 additions and 23 deletions
+26 -21
View File
@@ -23,10 +23,10 @@ type rssStore interface {
Find(locator store.Locator, sort string, user store.User) ([]store.Comment, error)
Last(siteID string, limit int, since time.Time, user store.User) ([]store.Comment, error)
Get(locator store.Locator, commentID string, user store.User) (store.Comment, error)
UserReplies(siteID, userID string, limit int, duration time.Duration) ([]store.Comment, string, error)
}
const maxRssItems = 20
const maxLastCommentsReply = 5000
const maxReplyDuration = 31 * 24 * time.Hour
// ui uses links like <post-url>#remark42__comment-<comment-id>
@@ -100,31 +100,36 @@ func (s *rss) repliesCtrl(w http.ResponseWriter, r *http.Request) {
siteID := r.URL.Query().Get("site")
log.Printf("[DEBUG] get rss replies to user %s for site %s", userID, siteID)
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{}, rest.GetUserOrEmpty(r))
//comments, e := s.dataService.UserReplies(siteID, userID, maxRssItems, maxReplyDuration)
//if e != nil {
// return nil, errors.Wrap(e, "can't get last comments")
//}
//replies := []store.Comment{}
//for _, c := range comments {
// if len(replies) > maxRssItems || c.Timestamp.Add(maxReplyDuration).Before(time.Now()) {
// break
// }
// if c.User.ID != userID {
// userName = c.User.Name
// }
// 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, rest.GetUserOrEmpty(r)); e != nil {
// return nil, errors.Wrap(e, "can't get parent comment")
// }
// if pc.User.ID == userID {
// replies = append(replies, c)
// }
// }
//}
replies, userName, e := s.dataService.UserReplies(siteID, userID, maxRssItems, maxReplyDuration)
if e != nil {
return nil, errors.Wrap(e, "can't get last comments")
}
replies := []store.Comment{}
for _, c := range comments {
if len(replies) > maxRssItems || c.Timestamp.Add(maxReplyDuration).Before(time.Now()) {
break
}
if c.User.ID != userID {
userName = c.User.Name
}
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, rest.GetUserOrEmpty(r)); e != nil {
return nil, errors.Wrap(e, "can't get parent comment")
}
if pc.User.ID == userID {
replies = append(replies, c)
}
}
}
feed, e := s.toRssFeed(siteID, replies, "replies to "+userName)
if e != nil {
+1 -1
View File
@@ -242,7 +242,7 @@ func TestServer_RssReplies(t *testing.T) {
<channel>
<title>Remark42 comments</title>
<link>radio-t</link>
<description>replies to user2</description>
<description>replies to user1</description>
<pubDate>%s</pubDate>
<item>
<title>user3 &gt; user1</title>
+39 -1
View File
@@ -64,11 +64,13 @@ type PostMetaData struct {
}
const defaultCommentMaxSize = 2000
const maxLastCommentsReply = 1000
const maxLastCommentsReply = 5000
// UnlimitedVotes doesn't restrict MaxVotes
const UnlimitedVotes = -1
var nonAdminUser = store.User{}
// ErrRestrictedWordsFound returned in case comment text contains restricted words
var ErrRestrictedWordsFound = errors.New("comment contains restricted words")
@@ -351,6 +353,42 @@ func (s *DataStore) HasReplies(comment store.Comment) bool {
return false
}
// UserReplies returns list of all comments replied to given user
func (s *DataStore) UserReplies(siteID, userID string, limit int, duration time.Duration) ([]store.Comment, string, error) {
comments, e := s.Last(siteID, maxLastCommentsReply, time.Time{}, nonAdminUser)
if e != nil {
return nil, "", errors.Wrap(e, "can't get last comments")
}
replies := []store.Comment{}
// get a comment for given userID in order to retrieve name
userName := ""
if cc, err := s.User(siteID, userID, 1, 0, nonAdminUser); err == nil && len(cc) > 0 {
userName = cc[0].User.Name
}
// collect replies
for _, c := range comments {
if len(replies) > limit || time.Since(c.Timestamp) > duration {
break
}
if c.ParentID != "" && !c.Deleted && c.User.ID != userID { // not interested in replies to yourself
var pc store.Comment
if pc, e = s.Get(c.Locator, c.ParentID, nonAdminUser); e != nil {
return nil, "", errors.Wrap(e, "can't get parent comment")
}
if pc.User.ID == userID {
replies = append(replies, c)
}
}
}
return replies, userName, nil
}
// SetTitle puts title from the locator.URL page and overwrites any existing title
func (s *DataStore) SetTitle(locator store.Locator, commentID string) (comment store.Comment, err error) {
if s.TitleExtractor == nil {
+77
View File
@@ -663,6 +663,83 @@ func TestService_HasReplies(t *testing.T) {
assert.True(t, b.HasReplies(comment))
}
func TestService_UserReplies(t *testing.T) {
defer teardown(t)
// two comments for https://radio-t.com, no reply
b := DataStore{Interface: prepStoreEngine(t),
AdminStore: admin.NewStaticStore("secret 123", []string{"user2"}, "user@email.com")}
c1 := store.Comment{
ID: "comment-id-1",
Text: "test 123",
Locator: store.Locator{URL: "https://radio-t.com/blah10", SiteID: "radio-t"},
User: store.User{ID: "u1", Name: "developer one u1"},
}
c2 := store.Comment{
ID: "comment-id-2",
ParentID: "comment-id-1",
Text: "xyz test",
Locator: store.Locator{URL: "https://radio-t.com/blah10", SiteID: "radio-t"},
User: store.User{ID: "u2", Name: "developer one u2"},
}
c3 := store.Comment{
ID: "comment-id-3",
ParentID: "comment-id-1",
Text: "xyz test",
Locator: store.Locator{URL: "https://radio-t.com/blah10", SiteID: "radio-t"},
User: store.User{ID: "u2", Name: "developer one u3"},
}
c4 := store.Comment{
ID: "comment-id-4",
ParentID: "",
Text: "xyz test",
Locator: store.Locator{URL: "https://radio-t.com/blah10", SiteID: "radio-t"},
User: store.User{ID: "u4", Name: "developer one u4"},
}
c5 := store.Comment{
ID: "comment-id-5",
ParentID: "comment-id-1",
Text: "xyz test",
Locator: store.Locator{URL: "https://radio-t.com/blah10", SiteID: "radio-t"},
User: store.User{ID: "u2", Name: "developer one u2"},
}
_, err := b.Create(c1)
require.NoError(t, err)
_, err = b.Create(c2)
require.NoError(t, err)
_, err = b.Create(c3)
require.NoError(t, err)
_, err = b.Create(c4)
require.NoError(t, err)
time.Sleep(100 * time.Millisecond)
_, err = b.Create(c5)
require.NoError(t, err)
cc, u, err := b.UserReplies("radio-t", "u1", 10, time.Hour)
assert.NoError(t, err)
assert.Equal(t, 3, len(cc), "3 replies to u1")
assert.Equal(t, "developer one u1", u)
cc, u, err = b.UserReplies("radio-t", "u1", 10, time.Millisecond*50)
assert.NoError(t, err)
assert.Equal(t, 1, len(cc), "1 reply to u1 in last 90ms")
assert.Equal(t, "developer one u1", u)
cc, u, err = b.UserReplies("radio-t", "u2", 10, time.Hour)
assert.NoError(t, err)
assert.Equal(t, 0, len(cc), "0 replies to u2")
assert.Equal(t, "developer one u2", u)
cc, u, err = b.UserReplies("radio-t", "uxxx", 10, time.Hour)
assert.NoError(t, err)
assert.Equal(t, 0, len(cc), "0 replies to uxxx")
}
func TestService_Find(t *testing.T) {
defer teardown(t)