diff --git a/app/rest/tree.go b/app/rest/tree.go index fb954525..96e615c3 100644 --- a/app/rest/tree.go +++ b/app/rest/tree.go @@ -3,6 +3,7 @@ package rest import ( "sort" "strings" + "time" "github.com/umputun/remark/app/store" ) @@ -16,6 +17,12 @@ type Tree struct { type Node struct { Comment store.Comment `json:"comment"` Replies []*Node `json:"replies,omitempty"` + ts time.Time +} + +// timeStamp wraps time.Time to simplify pointer ops +type timeStamp struct { + time.Time } // MakeTree gets unsorted list of comments and produces Tree @@ -27,10 +34,12 @@ func MakeTree(comments []store.Comment, sortType string) *Tree { for _, rootComment := range topComments { node := Node{Comment: rootComment} - commentsTree := res.proc(comments, &node, rootComment.ID) + ts := timeStamp{} + commentsTree, t := res.proc(comments, &node, &ts, rootComment.ID) if rootComment.Deleted && len(commentsTree.Replies) == 0 { // skip deleted with no subcomments continue } + commentsTree.ts = t res.Nodes = append(res.Nodes, commentsTree) } @@ -39,18 +48,26 @@ func MakeTree(comments []store.Comment, sortType string) *Tree { } // proc makes tree for one top-level comment recursively -func (t *Tree) proc(comments []store.Comment, node *Node, parentID string) *Node { +func (t *Tree) proc(comments []store.Comment, node *Node, ts *timeStamp, parentID string) (*Node, time.Time) { + + if ts.IsZero() { + ts.Time = node.Comment.Timestamp + } + repComments := t.filter(comments, parentID) for _, rc := range repComments { + if rc.Timestamp.After(ts.Time) { + ts.Time = rc.Timestamp + } rnode := &Node{Comment: rc, Replies: []*Node{}} node.Replies = append(node.Replies, rnode) - t.proc(comments, rnode, rc.ID) + t.proc(comments, rnode, ts, rc.ID) } // replies always sorted by time sort.Slice(node.Replies, func(i, j int) bool { return node.Replies[i].Comment.Timestamp.Before(node.Replies[j].Comment.Timestamp) }) - return node + return node, ts.Time } // filter returns comments for parentID @@ -65,15 +82,16 @@ func (t *Tree) filter(comments []store.Comment, parentID string) (f []store.Comm } // sort list of nodes, i.e. top-level comments +// time sort uses ts from latest reply func (t *Tree) sortNodes(sortType string) { sort.Slice(t.Nodes, func(i, j int) bool { switch sortType { case "+time", "-time", "time": if strings.HasPrefix(sortType, "-") { - return t.Nodes[i].Comment.Timestamp.After(t.Nodes[j].Comment.Timestamp) + return t.Nodes[i].ts.After(t.Nodes[j].ts) } - return t.Nodes[i].Comment.Timestamp.Before(t.Nodes[j].Comment.Timestamp) + return t.Nodes[i].ts.Before(t.Nodes[j].ts) case "+score", "-score", "score": if strings.HasPrefix(sortType, "-") { diff --git a/app/rest/tree_test.go b/app/rest/tree_test.go index ac252b56..224c2af0 100644 --- a/app/rest/tree_test.go +++ b/app/rest/tree_test.go @@ -50,8 +50,8 @@ func TestTreeSortNodes(t *testing.T) { {ID: "2", Timestamp: time.Date(2017, 12, 25, 19, 47, 2, 0, time.UTC), Score: 3}, {ID: "11", ParentID: "1", Timestamp: time.Date(2017, 12, 25, 19, 46, 11, 0, time.UTC)}, {ID: "13", ParentID: "1", Timestamp: time.Date(2017, 12, 25, 19, 46, 13, 0, time.UTC)}, - {ID: "12", ParentID: "1", Timestamp: time.Date(2017, 12, 25, 19, 46, 12, 0, time.UTC)}, - {ID: "131", ParentID: "13", Timestamp: time.Date(2017, 12, 25, 19, 46, 31, 0, time.UTC)}, + {ID: "12", ParentID: "1", Timestamp: time.Date(2017, 12, 25, 19, 46, 14, 0, time.UTC)}, + {ID: "131", ParentID: "13", Timestamp: time.Date(2017, 12, 25, 19, 50, 31, 0, time.UTC)}, {ID: "132", ParentID: "13", Timestamp: time.Date(2017, 12, 25, 19, 46, 32, 0, time.UTC)}, {ID: "21", ParentID: "2", Timestamp: time.Date(2017, 12, 25, 19, 47, 21, 0, time.UTC)}, {ID: "22", ParentID: "2", Timestamp: time.Date(2017, 12, 25, 19, 47, 22, 0, time.UTC)}, @@ -61,14 +61,13 @@ func TestTreeSortNodes(t *testing.T) { {ID: "5", Deleted: true}, } - res := MakeTree(comments, "time") - assert.Equal(t, "1", res.Nodes[0].Comment.ID) - - res = MakeTree(comments, "time") - assert.Equal(t, "1", res.Nodes[0].Comment.ID) + res := MakeTree(comments, "+time") + assert.Equal(t, "2", res.Nodes[0].Comment.ID) + t.Log(res.Nodes[0].Comment.ID, res.Nodes[0].ts) res = MakeTree(comments, "-time") - assert.Equal(t, "6", res.Nodes[0].Comment.ID) + t.Log(res.Nodes[0].Comment.ID, res.Nodes[0].ts) + assert.Equal(t, "1", res.Nodes[0].Comment.ID) res = MakeTree(comments, "score") assert.Equal(t, "4", res.Nodes[0].Comment.ID)