* add rss feed for replies to user * fix add consts
This commit is contained in:
@@ -15,6 +15,8 @@ import (
|
||||
)
|
||||
|
||||
const maxRssItems = 20
|
||||
const maxLastForReply = 100
|
||||
const maxReplyMins = 30 * time.Minute
|
||||
|
||||
// ui uses links like <post-url>#remark42__comment-<comment-id>
|
||||
const uiNav = "#remark42__comment-"
|
||||
@@ -23,6 +25,7 @@ func (s *Rest) rssRoutes() chi.Router {
|
||||
router := chi.NewRouter()
|
||||
router.Get("/post", s.rssPostCommentsCtrl)
|
||||
router.Get("/site", s.rssSiteCommentsCtrl)
|
||||
router.Get("/reply", s.rssRepliesCtrl)
|
||||
return router
|
||||
}
|
||||
|
||||
@@ -88,6 +91,54 @@ func (s *Rest) rssSiteCommentsCtrl(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
// GET /rss/reply?user=userID&site=siteID
|
||||
func (s *Rest) rssRepliesCtrl(w http.ResponseWriter, r *http.Request) {
|
||||
userID := r.URL.Query().Get("user")
|
||||
siteID := r.URL.Query().Get("site")
|
||||
log.Printf("[DEBUG] get rss replies to user %s for site %s", userID, siteID)
|
||||
|
||||
data, err := s.Cache.Get(cache.Key(cache.URLKey(r), siteID, userID), func() ([]byte, error) {
|
||||
comments, e := s.DataService.Last(siteID, maxLastForReply)
|
||||
if e != nil {
|
||||
return nil, e
|
||||
}
|
||||
comments = s.adminService.alterComments(comments, r)
|
||||
|
||||
replies := []store.Comment{}
|
||||
for _, c := range comments {
|
||||
if len(replies) > maxRssItems || c.Timestamp.Add(maxReplyMins).Before(time.Now()) {
|
||||
break
|
||||
}
|
||||
if c.ParentID != "" && !c.Deleted && c.User.ID != userID { // not interested replies to yourself
|
||||
pc, errP := s.DataService.Get(c.Locator, c.ParentID)
|
||||
if errP != nil {
|
||||
return nil, errP
|
||||
}
|
||||
if pc.User.ID == userID {
|
||||
replies = append(replies, c)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rss, e := s.toRssFeed(siteID, replies)
|
||||
if e != nil {
|
||||
return nil, e
|
||||
}
|
||||
return []byte(rss), e
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
rest.SendErrorJSON(w, r, http.StatusBadRequest, err, "can't get replies")
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/xml; charset=utf-8")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
if _, err := w.Write(data); err != nil {
|
||||
log.Printf("[WARN] failed to send response to %s, %s", r.RemoteAddr, err)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Rest) toRssFeed(url string, comments []store.Comment) (string, error) {
|
||||
|
||||
lastCommentTS := time.Unix(0, 0)
|
||||
|
||||
@@ -158,6 +158,83 @@ func TestServer_RssWithReply(t *testing.T) {
|
||||
assert.Equal(t, expected, res)
|
||||
}
|
||||
|
||||
func TestServer_RssReplies(t *testing.T) {
|
||||
srv, ts := prep(t)
|
||||
assert.NotNil(t, srv)
|
||||
defer cleanup(ts)
|
||||
|
||||
waitOnSecChange()
|
||||
|
||||
pubDate := time.Now().Format(time.RFC1123Z)
|
||||
|
||||
c1 := store.Comment{
|
||||
Text: "c1",
|
||||
Locator: store.Locator{URL: "https://radio-t.com/blah1", SiteID: "radio-t"},
|
||||
User: store.User{ID: "user1", Name: "user1"},
|
||||
}
|
||||
id1, err := srv.DataService.Create(c1)
|
||||
assert.Nil(t, err)
|
||||
c2 := store.Comment{
|
||||
Text: "reply to c1 from user2",
|
||||
ParentID: id1,
|
||||
Locator: store.Locator{URL: "https://radio-t.com/blah1", SiteID: "radio-t"},
|
||||
User: store.User{ID: "user2", Name: "user2"},
|
||||
}
|
||||
id2, err := srv.DataService.Create(c2)
|
||||
assert.Nil(t, err)
|
||||
c3 := store.Comment{
|
||||
Text: "reply to c1 from user3",
|
||||
ParentID: id1,
|
||||
Locator: store.Locator{URL: "https://radio-t.com/blah1", SiteID: "radio-t"},
|
||||
User: store.User{ID: "user3", Name: "user3"},
|
||||
}
|
||||
id3, err := srv.DataService.Create(c3)
|
||||
assert.Nil(t, err)
|
||||
c4 := store.Comment{
|
||||
Text: "reply to c2 from developer one",
|
||||
ParentID: id2,
|
||||
Locator: store.Locator{URL: "https://radio-t.com/blah1", SiteID: "radio-t"},
|
||||
}
|
||||
addComment(t, c4, ts)
|
||||
c5 := store.Comment{
|
||||
Text: "developer one",
|
||||
Locator: store.Locator{URL: "https://radio-t.com/blah1", SiteID: "radio-t"},
|
||||
}
|
||||
addComment(t, c5, ts)
|
||||
|
||||
// replies to c1 (user1). Must be [c3, c2]
|
||||
res, code := get(t, ts.URL+"/api/v1/rss/reply?user=user1&site=radio-t")
|
||||
assert.Equal(t, 200, code)
|
||||
t.Log(res)
|
||||
expected := fmt.Sprintf(`<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/">
|
||||
<channel>
|
||||
<title>Remark42 comments</title>
|
||||
<link>radio-t</link>
|
||||
<description>comment updates</description>
|
||||
<pubDate>%s</pubDate>
|
||||
<item>
|
||||
<title>user3 > user1</title>
|
||||
<link>https://radio-t.com/blah1#remark42__comment-%s</link>
|
||||
<description>reply to c1 from user3</description>
|
||||
<author>user3</author>
|
||||
<pubDate>%s</pubDate>
|
||||
</item>
|
||||
<item>
|
||||
<title>user2 > user1</title>
|
||||
<link>https://radio-t.com/blah1#remark42__comment-%s</link>
|
||||
<description>reply to c1 from user2</description>
|
||||
<author>user2</author>
|
||||
<pubDate>%s</pubDate>
|
||||
</item>
|
||||
</channel>
|
||||
</rss>`, pubDate, id3, pubDate, id2, pubDate)
|
||||
expected, res = cleanRssFormatting(expected, res)
|
||||
assert.Equal(t, expected, res)
|
||||
|
||||
_, code = get(t, ts.URL+"/api/v1/rss/reply?user=user1&site=radio-t-bad")
|
||||
assert.Equal(t, 400, code)
|
||||
}
|
||||
|
||||
func waitOnSecChange() {
|
||||
for {
|
||||
if time.Now().Nanosecond() < 100000000 {
|
||||
|
||||
Reference in New Issue
Block a user