diff --git a/app/migrator/remark.go b/app/migrator/remark.go index 530e9c55..998c34f5 100644 --- a/app/migrator/remark.go +++ b/app/migrator/remark.go @@ -19,7 +19,7 @@ type Remark struct { // Export all comments to writer as json strings. Each comment is one string, separated by "\n" func (r *Remark) Export(w io.Writer, siteID string) error { - topics, err := r.DataStore.List(store.Locator{SiteID: siteID}) + topics, err := r.DataStore.List(siteID) if err != nil { return err } @@ -27,7 +27,7 @@ func (r *Remark) Export(w io.Writer, siteID string) error { commentsCount := 0 for _, topic := range topics { - comments, err := r.DataStore.Find(store.Request{Locator: store.Locator{SiteID: siteID, URL: topic}}) + comments, err := r.DataStore.Find(store.Locator{SiteID: siteID, URL: topic}, "time") if err != nil { return err } diff --git a/app/migrator/remark_test.go b/app/migrator/remark_test.go index 1124e403..83105af7 100644 --- a/app/migrator/remark_test.go +++ b/app/migrator/remark_test.go @@ -45,7 +45,7 @@ func TestRemark_Import(t *testing.T) { err = r.Import(buf, "radio-t") assert.Nil(t, err) - comments, err := b.Find(store.Request{Locator: store.Locator{SiteID: "radio-t", URL: "https://radio-t.com"}}) + comments, err := b.Find(store.Locator{SiteID: "radio-t", URL: "https://radio-t.com"}, "time") assert.Nil(t, err) assert.Equal(t, 2, len(comments)) assert.Equal(t, "efbc17f177ee1a1c0ee6e1e025749966ec071adc", comments[0].ID) diff --git a/app/rest/admin.go b/app/rest/admin.go index 4ae2f135..cb8ac711 100644 --- a/app/rest/admin.go +++ b/app/rest/admin.go @@ -59,7 +59,7 @@ func (a *admin) setBlockCtrl(w http.ResponseWriter, r *http.Request) { siteID := r.URL.Query().Get("site") blockStatus := r.URL.Query().Get("block") == "1" - if err := a.dataService.SetBlock(store.Locator{SiteID: siteID}, userID, blockStatus); err != nil { + if err := a.dataService.SetBlock(siteID, userID, blockStatus); err != nil { common.SendErrorJSON(w, r, http.StatusBadRequest, err, "can't set blocking status") return } @@ -110,8 +110,8 @@ func (a *admin) importCtrl(w http.ResponseWriter, r *http.Request) { a.respCache.flush() } -func (a *admin) checkBlocked(locator store.Locator, user store.User) bool { - return a.dataService.IsBlocked(locator, user.ID) +func (a *admin) checkBlocked(siteID string, user store.User) bool { + return a.dataService.IsBlocked(siteID, user.ID) } // processes comments and hides text of all comments for blocked users. @@ -119,7 +119,7 @@ func (a *admin) checkBlocked(locator store.Locator, user store.User) bool { func (a *admin) maskBlockedUsers(comments []store.Comment) (res []store.Comment) { res = make([]store.Comment, len(comments)) for i, c := range comments { - if a.dataService.IsBlocked(c.Locator, c.User.ID) { + if a.dataService.IsBlocked(c.Locator.SiteID, c.User.ID) { c.User.Blocked = true c.Text = "this comment was deleted" c.Score = 0 diff --git a/app/rest/server.go b/app/rest/server.go index 8bfd9028..1aed94c6 100644 --- a/app/rest/server.go +++ b/app/rest/server.go @@ -139,7 +139,7 @@ func (s *Server) createCommentCtrl(w http.ResponseWriter, r *http.Request) { log.Printf("[DEBUG] create comment %+v", comment) // check if user blocked - if s.mod.checkBlocked(store.Locator{}, comment.User) { + if s.mod.checkBlocked(comment.Locator.SiteID, comment.User) { common.SendErrorJSON(w, r, http.StatusForbidden, errors.New("rejected"), "user blocked") return } @@ -225,7 +225,7 @@ func (s *Server) findCommentsCtrl(w http.ResponseWriter, r *http.Request) { log.Printf("[DEBUG] get comments for %+v", locator) data, err := s.respCache.get(r.URL.String(), time.Hour, func() ([]byte, error) { - comments, e := s.DataService.Find(store.Request{Locator: locator, Sort: r.URL.Query().Get("sort")}) + comments, e := s.DataService.Find(locator, r.URL.Query().Get("sort")) if e != nil { return nil, e } @@ -258,7 +258,7 @@ func (s *Server) lastCommentsCtrl(w http.ResponseWriter, r *http.Request) { } data, err := s.respCache.get(r.URL.String(), time.Hour, func() ([]byte, error) { - comments, e := s.DataService.Last(store.Locator{SiteID: r.URL.Query().Get("site")}, max) + comments, e := s.DataService.Last(r.URL.Query().Get("site"), max) if e != nil { return nil, e } @@ -277,11 +277,11 @@ func (s *Server) lastCommentsCtrl(w http.ResponseWriter, r *http.Request) { func (s *Server) commentByIDCtrl(w http.ResponseWriter, r *http.Request) { id := chi.URLParam(r, "id") - locator := store.Locator{SiteID: r.URL.Query().Get("site"), URL: r.URL.Query().Get("url")} + siteID := r.URL.Query().Get("site") - log.Printf("[DEBUG] get comments by id %s, %+v", id, locator) + log.Printf("[DEBUG] get comments by id %s, %s", id, siteID) - comment, err := s.DataService.GetByID(locator, id) + comment, err := s.DataService.GetByID(siteID, id) if err != nil { common.SendErrorJSON(w, r, http.StatusInternalServerError, err, "can't get comment by id") return @@ -298,7 +298,7 @@ func (s *Server) findUserCommentsCtrl(w http.ResponseWriter, r *http.Request) { log.Printf("[DEBUG] get comments by userID %s", userID) data, err := s.respCache.get(r.URL.String(), time.Hour, func() ([]byte, error) { - comments, e := s.DataService.GetByUser(store.Locator{SiteID: r.URL.Query().Get("site")}, userID) + comments, e := s.DataService.GetByUser(r.URL.Query().Get("site"), userID) if e != nil { return nil, e } @@ -335,13 +335,12 @@ func (s *Server) countCtrl(w http.ResponseWriter, r *http.Request) { // GET /list?site=siteID - list posts with comments func (s *Server) listCtrl(w http.ResponseWriter, r *http.Request) { - locator := store.Locator{SiteID: r.URL.Query().Get("site")} - posts, err := s.DataService.List(locator) + posts, err := s.DataService.List(r.URL.Query().Get("site")) if err != nil { common.SendErrorJSON(w, r, http.StatusBadRequest, err, "can't get count") return } - render.JSON(w, r, JSON{"posts": posts, "loc": locator}) + render.JSON(w, r, JSON{"posts": posts, "site": r.URL.Query().Get("site")}) } // PUT /vote/{id}?site=siteID&url=post-url&vote=1 - vote for/against comment diff --git a/app/store/bolt.go b/app/store/bolt.go index 33c71283..34404d71 100644 --- a/app/store/bolt.go +++ b/app/store/bolt.go @@ -151,18 +151,18 @@ func (b *BoltDB) Delete(locator Locator, commentID string) error { } // Find returns all comments for post and sorts results -func (b *BoltDB) Find(request Request) (comments []Comment, err error) { +func (b *BoltDB) Find(locator Locator, sortFld string) (comments []Comment, err error) { comments = []Comment{} - bdb, err := b.db(request.Locator.SiteID) + bdb, err := b.db(locator.SiteID) if err != nil { return nil, err } err = bdb.View(func(tx *bolt.Tx) error { - bucket := tx.Bucket([]byte(request.Locator.URL)) + bucket := tx.Bucket([]byte(locator.URL)) if bucket == nil { - return errors.Errorf("no bucket %s in store", request.Locator.URL) + return errors.Errorf("no bucket %s in store", locator.URL) } return bucket.ForEach(func(k, v []byte) error { @@ -175,17 +175,17 @@ func (b *BoltDB) Find(request Request) (comments []Comment, err error) { }) }) - // sort result according to request.Sort + // sort result according to sortFld sort.Slice(comments, func(i, j int) bool { - switch request.Sort { + switch sortFld { case "+time", "-time", "time": - if strings.HasPrefix(request.Sort, "-") { + if strings.HasPrefix(sortFld, "-") { return comments[i].Timestamp.After(comments[j].Timestamp) } return comments[i].Timestamp.Before(comments[j].Timestamp) case "+score", "-score", "score": - if strings.HasPrefix(request.Sort, "-") { + if strings.HasPrefix(sortFld, "-") { return comments[i].Score > comments[j].Score } return comments[i].Score < comments[j].Score @@ -199,9 +199,9 @@ func (b *BoltDB) Find(request Request) (comments []Comment, err error) { } // GetByID returns comment by id across posts -func (b *BoltDB) GetByID(locator Locator, commentID string) (comment Comment, err error) { +func (b *BoltDB) GetByID(siteID string, commentID string) (comment Comment, err error) { - bdb, err := b.db(locator.SiteID) + bdb, err := b.db(siteID) if err != nil { return comment, err } @@ -220,7 +220,7 @@ func (b *BoltDB) GetByID(locator Locator, commentID string) (comment Comment, er return e } - if foundID == commentID && url == locator.URL { + if foundID == commentID { urlBucket := tx.Bucket([]byte(url)) if urlBucket == nil { return errors.Errorf("no bucket %s in store", url) @@ -235,14 +235,14 @@ func (b *BoltDB) GetByID(locator Locator, commentID string) (comment Comment, er return comment, err } -// Last returns up to max last comments for given locator -func (b *BoltDB) Last(locator Locator, max int) (comments []Comment, err error) { +// Last returns up to max last comments for given siteID +func (b *BoltDB) Last(siteID string, max int) (comments []Comment, err error) { if max > lastLimit || max == 0 { max = lastLimit } - bdb, err := b.db(locator.SiteID) + bdb, err := b.db(siteID) if err != nil { return nil, err } @@ -302,9 +302,9 @@ func (b *BoltDB) Count(locator Locator) (count int, err error) { } // SetBlock blocks/unblocks user for given site -func (b *BoltDB) SetBlock(locator Locator, userID string, status bool) error { +func (b *BoltDB) SetBlock(siteID string, userID string, status bool) error { - bdb, err := b.db(locator.SiteID) + bdb, err := b.db(siteID) if err != nil { return err } @@ -331,9 +331,9 @@ func (b *BoltDB) SetBlock(locator Locator, userID string, status bool) error { } // IsBlocked checks if user blocked -func (b *BoltDB) IsBlocked(locator Locator, userID string) (blocked bool) { +func (b *BoltDB) IsBlocked(siteID string, userID string) (blocked bool) { - bdb, err := b.db(locator.SiteID) + bdb, err := b.db(siteID) if err != nil { return false } @@ -350,9 +350,9 @@ func (b *BoltDB) IsBlocked(locator Locator, userID string) (blocked bool) { } // List returns list of buckets, which is list of all commented posts -func (b BoltDB) List(locator Locator) (list []string, err error) { +func (b BoltDB) List(siteID string) (list []string, err error) { - bdb, err := b.db(locator.SiteID) + bdb, err := b.db(siteID) if err != nil { return nil, err } @@ -370,12 +370,12 @@ func (b BoltDB) List(locator Locator) (list []string, err error) { // GetByUser extracts all comments for given site and given userID // "users" bucket has sub-bucket for each userID, and keeps it as ts:ref -func (b *BoltDB) GetByUser(locator Locator, userID string) (comments []Comment, err error) { +func (b *BoltDB) GetByUser(siteID string, userID string) (comments []Comment, err error) { comments = []Comment{} commentRefs := []string{} - bdb, err := b.db(locator.SiteID) + bdb, err := b.db(siteID) if err != nil { return nil, err } @@ -411,7 +411,7 @@ func (b *BoltDB) GetByUser(locator Locator, userID string) (comments []Comment, if e != nil { return comments, errors.Wrapf(e, "can't parse reference %s", v) } - if c, e := b.GetByID(Locator{URL: url, SiteID: locator.SiteID}, commentID); e == nil { + if c, e := b.Get(Locator{SiteID: siteID, URL: url}, commentID); e == nil { comments = append(comments, c) } } diff --git a/app/store/bolt_test.go b/app/store/bolt_test.go index 7e407d8a..1048eba1 100644 --- a/app/store/bolt_test.go +++ b/app/store/bolt_test.go @@ -14,7 +14,7 @@ func TestBoltDB_CreateAndFind(t *testing.T) { var b Interface = prep(t) defer os.Remove(testDb) - res, err := b.Find(Request{Locator: Locator{URL: "https://radio-t.com", SiteID: "radio-t"}}) + res, err := b.Find(Locator{URL: "https://radio-t.com", SiteID: "radio-t"}, "time") assert.Nil(t, err) assert.Equal(t, 2, len(res)) assert.Equal(t, `some text, link`, res[0].Text) @@ -27,19 +27,19 @@ func TestBoltDB_Delete(t *testing.T) { b := prep(t) loc := Locator{URL: "https://radio-t.com", SiteID: "radio-t"} - res, err := b.Find(Request{Locator: loc}) + res, err := b.Find(loc, "time") assert.Nil(t, err) assert.Equal(t, 2, len(res)) err = b.Delete(loc, res[0].ID) assert.Nil(t, err) - res, err = b.Find(Request{Locator: loc}) + res, err = b.Find(loc, "time") assert.Nil(t, err) assert.Equal(t, 1, len(res)) assert.Equal(t, "some text2", res[0].Text) - comments, err := b.Last(loc, 10) + comments, err := b.Last("radio-t", 10) assert.Nil(t, err) assert.Equal(t, 1, len(comments), "only 1 left in last") } @@ -48,15 +48,15 @@ func TestBoltDB_GetByID(t *testing.T) { defer os.Remove(testDb) b := prep(t) - res, err := b.Find(Request{Locator: Locator{URL: "https://radio-t.com", SiteID: "radio-t"}}) + res, err := b.Find(Locator{URL: "https://radio-t.com", SiteID: "radio-t"}, "time") assert.Nil(t, err) assert.Equal(t, 2, len(res)) - comment, err := b.GetByID(Locator{URL: "https://radio-t.com", SiteID: "radio-t"}, res[1].ID) + comment, err := b.GetByID("radio-t", res[1].ID) assert.Nil(t, err) assert.Equal(t, "some text2", comment.Text) - comment, err = b.GetByID(Locator{URL: "https://radio-t.com", SiteID: "radio-t"}, "1234567") + comment, err = b.GetByID("radio-t", "1234567") assert.NotNil(t, err) } @@ -64,12 +64,12 @@ func TestBoltDB_Last(t *testing.T) { defer os.Remove(testDb) b := prep(t) - res, err := b.Last(Locator{URL: "https://radio-t.com", SiteID: "radio-t"}, 0) + res, err := b.Last("radio-t", 0) assert.Nil(t, err) assert.Equal(t, 2, len(res)) assert.Equal(t, "some text2", res[0].Text) - res, err = b.Last(Locator{URL: "https://radio-t.com", SiteID: "radio-t"}, 1) + res, err = b.Last("radio-t", 1) assert.Nil(t, err) assert.Equal(t, 1, len(res)) assert.Equal(t, "some text2", res[0].Text) @@ -88,15 +88,15 @@ func TestBoltDB_BlockUser(t *testing.T) { defer os.Remove(testDb) b := prep(t) - assert.False(t, b.IsBlocked(Locator{SiteID: "radio-t"}, "user1"), "nothing blocked") + assert.False(t, b.IsBlocked("radio-t", "user1"), "nothing blocked") - assert.NoError(t, b.SetBlock(Locator{SiteID: "radio-t"}, "user1", true)) - assert.True(t, b.IsBlocked(Locator{SiteID: "radio-t"}, "user1"), "user1 blocked") + assert.NoError(t, b.SetBlock("radio-t", "user1", true)) + assert.True(t, b.IsBlocked("radio-t", "user1"), "user1 blocked") - assert.False(t, b.IsBlocked(Locator{SiteID: "radio-t"}, "user2"), "user2 still unblocked") + assert.False(t, b.IsBlocked("radio-t", "user2"), "user2 still unblocked") - assert.NoError(t, b.SetBlock(Locator{SiteID: "radio-t"}, "user1", false)) - assert.False(t, b.IsBlocked(Locator{SiteID: "radio-t"}, "user1"), "user1 unblocked") + assert.NoError(t, b.SetBlock("radio-t", "user1", false)) + assert.False(t, b.IsBlocked("radio-t", "user1"), "user1 unblocked") } @@ -114,7 +114,7 @@ func TestBoltDB_List(t *testing.T) { _, err := b.Create(comment) assert.Nil(t, err) - res, err := b.List(Locator{SiteID: "radio-t"}) + res, err := b.List("radio-t") assert.Nil(t, err) assert.Equal(t, []string{"https://radio-t.com", "https://radio-t.com/2"}, res) } @@ -123,7 +123,7 @@ func TestBoltDB_GetForUser(t *testing.T) { defer os.Remove(testDb) b := prep(t) - res, err := b.GetByUser(Locator{SiteID: "radio-t"}, "user1") + res, err := b.GetByUser("radio-t", "user1") assert.Nil(t, err) assert.Equal(t, 2, len(res)) assert.Equal(t, "some text2", res[0].Text, "sorted by -time") diff --git a/app/store/service_test.go b/app/store/service_test.go index a5672c72..07c9007b 100644 --- a/app/store/service_test.go +++ b/app/store/service_test.go @@ -12,7 +12,7 @@ func TestService_Vote(t *testing.T) { defer os.Remove(testDb) b := Service{Interface: prep(t)} - res, err := b.Last(Locator{URL: "https://radio-t.com", SiteID: "radio-t"}, 0) + res, err := b.Last("radio-t", 0) t.Logf("%+v", res[0]) assert.Nil(t, err) assert.Equal(t, 2, len(res)) @@ -27,14 +27,14 @@ func TestService_Vote(t *testing.T) { _, err = b.Vote(Locator{URL: "https://radio-t.com", SiteID: "radio-t"}, res[0].ID, "user1", true) assert.NotNil(t, err, "double-voting rejected") - res, err = b.Last(Locator{URL: "https://radio-t.com", SiteID: "radio-t"}, 0) + res, err = b.Last("radio-t", 0) assert.Nil(t, err) assert.Equal(t, 2, len(res)) assert.Equal(t, 1, res[0].Score) _, err = b.Vote(Locator{URL: "https://radio-t.com", SiteID: "radio-t"}, res[0].ID, "user1", false) assert.Nil(t, err, "vote reset") - res, err = b.Last(Locator{URL: "https://radio-t.com", SiteID: "radio-t"}, 0) + res, err = b.Last("radio-t", 0) assert.Nil(t, err) assert.Equal(t, 2, len(res)) assert.Equal(t, 0, res[0].Score) @@ -46,7 +46,7 @@ func TestBoltDB_Pin(t *testing.T) { defer os.Remove(testDb) b := Service{Interface: prep(t)} - res, err := b.Last(Locator{URL: "https://radio-t.com", SiteID: "radio-t"}, 0) + res, err := b.Last("radio-t", 0) t.Logf("%+v", res[0]) assert.Nil(t, err) assert.Equal(t, 2, len(res)) @@ -55,13 +55,13 @@ func TestBoltDB_Pin(t *testing.T) { err = b.SetPin(Locator{URL: "https://radio-t.com", SiteID: "radio-t"}, res[0].ID, true) assert.Nil(t, err) - c, err := b.GetByID(Locator{URL: "https://radio-t.com", SiteID: "radio-t"}, res[0].ID) + c, err := b.GetByID("radio-t", res[0].ID) assert.Nil(t, err) assert.Equal(t, true, c.Pin) err = b.SetPin(Locator{URL: "https://radio-t.com", SiteID: "radio-t"}, res[0].ID, false) assert.Nil(t, err) - c, err = b.GetByID(Locator{URL: "https://radio-t.com", SiteID: "radio-t"}, res[0].ID) + c, err = b.GetByID("radio-t", res[0].ID) assert.Nil(t, err) assert.Equal(t, false, c.Pin) } @@ -70,7 +70,7 @@ func TestBoltDB_EditComment(t *testing.T) { defer os.Remove(testDb) b := Service{Interface: prep(t)} - res, err := b.Last(Locator{URL: "https://radio-t.com", SiteID: "radio-t"}, 0) + res, err := b.Last("radio-t", 0) t.Logf("%+v", res[0]) assert.Nil(t, err) assert.Equal(t, 2, len(res)) @@ -81,7 +81,7 @@ func TestBoltDB_EditComment(t *testing.T) { assert.Equal(t, "my edit", comment.Edit.Summary) assert.Equal(t, "xxx", comment.Text) - c, err := b.GetByID(Locator{URL: "https://radio-t.com", SiteID: "radio-t"}, res[0].ID) + c, err := b.GetByID("radio-t", res[0].ID) assert.Nil(t, err) assert.Equal(t, "my edit", c.Edit.Summary) assert.Equal(t, "xxx", c.Text) @@ -104,7 +104,7 @@ func TestBoltDB_EditCommentDurationFailed(t *testing.T) { b := Service{Interface: blt, EditDuration: 100 * time.Millisecond} - res, err := b.Last(Locator{URL: "https://radio-t.com", SiteID: "radio-t"}, 0) + res, err := b.Last("radio-t", 0) t.Logf("%+v", res[0]) assert.Nil(t, err) assert.Equal(t, 1, len(res)) diff --git a/app/store/store.go b/app/store/store.go index 95ea9698..52e4eacc 100644 --- a/app/store/store.go +++ b/app/store/store.go @@ -51,14 +51,6 @@ type Edit struct { Summary string `json:"summary"` } -// Request is a container for all finds -type Request struct { - Locator Locator `json:"locator"` - Sort string `json:"sort"` - Offset int `json:"offset"` - Limit int `json:"limit"` -} - // Interface combines all store interfaces type Interface interface { Accessor @@ -70,19 +62,19 @@ type Accessor interface { Create(comment Comment) (commentID string, err error) // create new comment, avoid dups by ID Get(locator Locator, commentID string) (comment Comment, err error) // get comment by ID Put(locator Locator, comment Comment) error // update comment, mutable parts only - Find(request Request) ([]Comment, error) // find comments for request - Last(locator Locator, max int) ([]Comment, error) // last comments for given site - GetByID(locator Locator, commentID string) (Comment, error) // comment by id - GetByUser(locator Locator, userID string) ([]Comment, error) // comment by user + Find(locator Locator, sort string) ([]Comment, error) // find comments for request + Last(siteID string, max int) ([]Comment, error) // last comments for given site + GetByID(siteID string, commentID string) (Comment, error) // comment by id + GetByUser(siteID string, userID string) ([]Comment, error) // comment by user Count(locator Locator) (int, error) // number of comments for the post - List(locator Locator) ([]string, error) // list of commented posts + List(siteID string) ([]string, error) // list of commented posts } // Admin defines all store ops avail for admin only type Admin interface { - Delete(locator Locator, commentID string) error // delete comment by id - SetBlock(locator Locator, userID string, status bool) error // block or unblock user - IsBlocked(locator Locator, userID string) bool // check if user blocked + Delete(locator Locator, commentID string) error // delete comment by id + SetBlock(siteID string, userID string, status bool) error // block or unblock user + IsBlocked(siteID string, userID string) bool // check if user blocked } // makeCommentID generates sha1(random) string diff --git a/app/store/store_test.go b/app/store/store_test.go index f9d05baf..d33b6fd3 100644 --- a/app/store/store_test.go +++ b/app/store/store_test.go @@ -1,7 +1,10 @@ package store -import "testing" -import "github.com/stretchr/testify/assert" +import ( + "testing" + + "github.com/stretchr/testify/assert" +) func TestStore_MakeCommentID(t *testing.T) { cid1 := makeCommentID()