From 350cca894dd455ec0650c0f7d6222809827bb442 Mon Sep 17 00:00:00 2001 From: Umputun Date: Sun, 19 May 2019 12:56:47 -0500 Subject: [PATCH] move reply retrieval to service, fix incorrect RSS title for reply --- backend/app/rest/api/rss.go | 47 +++++++------- backend/app/rest/api/rss_test.go | 2 +- backend/app/store/service/service.go | 40 +++++++++++- backend/app/store/service/service_test.go | 77 +++++++++++++++++++++++ 4 files changed, 143 insertions(+), 23 deletions(-) diff --git a/backend/app/rest/api/rss.go b/backend/app/rest/api/rss.go index 2b36b3c0..36e35449 100644 --- a/backend/app/rest/api/rss.go +++ b/backend/app/rest/api/rss.go @@ -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 #remark42__comment- @@ -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 { diff --git a/backend/app/rest/api/rss_test.go b/backend/app/rest/api/rss_test.go index 8f324e51..306de8b9 100644 --- a/backend/app/rest/api/rss_test.go +++ b/backend/app/rest/api/rss_test.go @@ -242,7 +242,7 @@ func TestServer_RssReplies(t *testing.T) { Remark42 comments radio-t - replies to user2 + replies to user1 %s user3 > user1 diff --git a/backend/app/store/service/service.go b/backend/app/store/service/service.go index 9999ffd8..6719e042 100644 --- a/backend/app/store/service/service.go +++ b/backend/app/store/service/service.go @@ -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 { diff --git a/backend/app/store/service/service_test.go b/backend/app/store/service/service_test.go index 01cd7031..d83d01b9 100644 --- a/backend/app/store/service/service_test.go +++ b/backend/app/store/service/service_test.go @@ -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)