From 983606ecd6883b7e01b45abc7554b56569b8efd2 Mon Sep 17 00:00:00 2001 From: eugene Date: Fri, 22 Dec 2017 13:24:29 -0600 Subject: [PATCH] add /count request --- README.md | 15 ++++++++------- app/rest/server.go | 30 ++++++++++++++++++++++-------- app/store/bolt.go | 14 ++++++++++++++ app/store/bolt_test.go | 11 ++++++++++- app/store/store.go | 1 + 5 files changed, 55 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index fbe2b023..15085c7e 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ Comment engine - `GET /login/{provider}?from=http://url` - perform "social" login with one of supported providers and redirect to `url` - `GET /logout` - logout -- `GET /user` - get user info, _auth required_ +- `GET /api/v1/user` - get user info, _auth required_ ``` type User struct { @@ -24,7 +24,7 @@ _currently supported providers are `google` and `github`_ ### Commenting -- `POST /comment` - add a comment. _auth required_ +- `POST /api/v1/comment` - add a comment. _auth required_ ``` type Comment struct { @@ -44,8 +44,9 @@ type Locator struct { } ``` -- `GET /find?url=post-url` - find all comments for given post returns list of `Comment` -- `GET /last/{max}` - get last `{max}` comments -- `GET /id/{id}` - get comment by `id` -- `PUT /vote/{id}?url=post-url&vote=1` - vote for comment. `vote`=1 will increase score, -1 decreases. _auth required_ -- `DELETE /comment/{id}` - delete comment by `id`. _auth and admin required_ \ No newline at end of file +- `GET /api/v1/find?url=post-url` - find all comments for given post returns list of `Comment` +- `GET /api/v1/last/{max}` - get last `{max}` comments +- `GET /api/v1/id/{id}` - get comment by `id` +- `GET /api/v1/count?url=post-url` - get comment's count for `{url}` +- `PUT /api/v1/vote/{id}?url=post-url&vote=1` - vote for comment. `vote`=1 will increase score, -1 decreases. _auth required_ +- `DELETE /api/v1/comment/{id}?url=post-url` - delete comment by `id`. _auth and admin required_ \ No newline at end of file diff --git a/app/rest/server.go b/app/rest/server.go index 0b0be3c6..9d5bcb81 100644 --- a/app/rest/server.go +++ b/app/rest/server.go @@ -41,15 +41,18 @@ func (s *Server) Run() { router.Get("/login/github", s.AuthGithub.LoginHandler) router.Get("/auth/github", s.AuthGithub.AuthHandler) - router.Get("/find", s.getURLComments) - router.Get("/id/{id}", s.getByID) - router.Get("/last/{max}", s.getLastComments) + router.Route("/api/v1", func(rapi chi.Router) { + rapi.Get("/find", s.getURLComments) + rapi.Get("/id/{id}", s.getByID) + rapi.Get("/last/{max}", s.getLastComments) + rapi.Get("/count", s.getCountCtrl) - router.With(Auth(s.SessionStore, s.Admins)).Group(func(r chi.Router) { - r.Post("/comment", s.createCommentCtrl) - r.Get("/user", s.getUserInfo) - r.Put("/vote/{id}", s.voteCtrl) - r.With(AdminOnly).Delete("/comment/{id}", s.deleteCommentCtrl) + rapi.With(Auth(s.SessionStore, s.Admins)).Group(func(r chi.Router) { + r.Post("/comment", s.createCommentCtrl) + r.Get("/user", s.getUserInfo) + r.Put("/vote/{id}", s.voteCtrl) + r.With(AdminOnly).Delete("/comment/{id}", s.deleteCommentCtrl) + }) }) log.Fatal(http.ListenAndServe(":8080", router)) @@ -179,6 +182,17 @@ func (s *Server) getUserInfo(w http.ResponseWriter, r *http.Request) { render.JSON(w, r, user) } +// GET /count?url=post-url +func (s *Server) getCountCtrl(w http.ResponseWriter, r *http.Request) { + url := r.URL.Query().Get("url") + count, err := s.Store.Count(store.Locator{URL: url}) + if err != nil { + httpError(w, r, http.StatusBadRequest, err, "can't get count") + return + } + render.JSON(w, r, JSON{"count": count, "url": url}) +} + // PUT /vote/{id}?url=post-url&vote=1 func (s *Server) voteCtrl(w http.ResponseWriter, r *http.Request) { diff --git a/app/store/bolt.go b/app/store/bolt.go index a7893240..4ec44283 100644 --- a/app/store/bolt.go +++ b/app/store/bolt.go @@ -243,6 +243,20 @@ func (b *BoltDB) Vote(locator Locator, commentID int64, userID string, val bool) return comment, err } +func (b *BoltDB) Count(locator Locator) (count int, err error) { + err = b.View(func(tx *bolt.Tx) error { + bucket := tx.Bucket([]byte(locator.URL)) + if bucket == nil { + return errors.Errorf("no bucket %s in store", locator.URL) + } + + count = bucket.Stats().KeyN + return nil + }) + + return count, err +} + func (b *BoltDB) keyFromComment(comment Comment) []byte { return []byte(fmt.Sprintf("%22d", comment.ID)) } diff --git a/app/store/bolt_test.go b/app/store/bolt_test.go index f29209f1..7c55641b 100644 --- a/app/store/bolt_test.go +++ b/app/store/bolt_test.go @@ -31,7 +31,7 @@ func TestBoltDB_Delete(t *testing.T) { assert.Nil(t, err) assert.Equal(t, 2, len(res)) - err = b.Delete("https://radio-t.com", res[0].ID) + err = b.Delete(Locator{URL: "https://radio-t.com"}, res[0].ID) assert.Nil(t, err) res, err = b.Find(Request{Locator: Locator{URL: "https://radio-t.com"}}) @@ -95,6 +95,15 @@ func TestBoltDB_Vote(t *testing.T) { assert.Equal(t, 1, res[0].Score) } +func TestBoltDB_Count(t *testing.T) { + defer os.Remove(testDb) + b := prep(t) + + c, err := b.Count(Locator{URL: "https://radio-t.com"}) + assert.Nil(t, err) + assert.Equal(t, 2, c) +} + // makes new boltdb, put two records func prep(t *testing.T) *BoltDB { b, err := NewBoltDB(testDb) diff --git a/app/store/store.go b/app/store/store.go index 79c7d1d5..778cccb4 100644 --- a/app/store/store.go +++ b/app/store/store.go @@ -46,4 +46,5 @@ type Interface interface { Last(locator Locator, max int) ([]Comment, error) Get(locator Locator, id int64) (Comment, error) Vote(locator Locator, commentID int64, userID string, val bool) (Comment, error) + Count(locator Locator) (int, error) }