add pin comment

This commit is contained in:
Umputun
2017-12-25 21:12:04 -06:00
parent 880192012b
commit b2d22fce97
5 changed files with 82 additions and 9 deletions
+11 -9
View File
@@ -28,7 +28,7 @@ TBD
### Authorization
- `GET /login/{provider}?from=http://url` - perform "social" login with one of supported providers and redirect to `url`
- `GET /logout` - logout
- `GET /logout` - logout
- `GET /api/v1/user` - get user info, _auth required_
```go
@@ -49,14 +49,15 @@ _currently supported providers are `google` and `github`_
```go
type Comment struct {
ID string `json:"id"` // read only
ParentID string `json:"pid"`
Text string `json:"text"`
User User `json:"user"` // read only
Locator Locator `json:"locator"`
Score int `json:"score"` // read only
Votes map[string]bool `json:"votes"` // read only
Timestamp time.Time `json:"time"` // read only
ID string `json:"id"` // comment ID, read only
ParentID string `json:"pid"` // parent ID
Text string `json:"text"` // comment text
User User `json:"user"` // user info, read only
Locator Locator `json:"locator"` // post locator
Score int `json:"score"` // comment score, read only
Votes map[string]bool `json:"votes"` // comment votes, read only
Timestamp time.Time `json:"time"` // time stamp, read only
Pin bool `json:"pin"` // pinned status, read only
}
type Locator struct {
@@ -90,3 +91,4 @@ Sort can be `time` or `score`. Supported sort order with prefix -/+, i.e. `-time
- `DELETE /api/v1/admin/comment/{id}?url=post-url` - delete comment by `id`. _auth and admin required_
- `PUT /api/v1/admin/user/{userid}?site=side-id&block=1` - block or unblock user. _auth and admin required_
- `GET /api/v1/admin/export?site=side-id&block=1` - export all comments. _auth and admin required_
- `PUT /api/v1/admin/pin/{id}?site=side-id&pin=1` - pin or unpin comment. _auth and admin required_
+15
View File
@@ -24,6 +24,7 @@ func (a *admin) routes() chi.Router {
router.Delete("/comment/{id}", a.deleteCommentCtrl)
router.Put("/user/{userid}", a.setBlockCtrl)
router.Get("/export", a.exportCtrl)
router.Put("/pin/{id}", a.setPinCtrl)
return router
}
@@ -59,6 +60,20 @@ func (a *admin) setBlockCtrl(w http.ResponseWriter, r *http.Request) {
render.JSON(w, r, JSON{"user_id": userID, "site_id": siteID, "block": blockStatus})
}
// PUT /pin/{id}?site=side-id&pin=1
func (a *admin) setPinCtrl(w http.ResponseWriter, r *http.Request) {
commentID := chi.URLParam(r, "id")
siteID := r.URL.Query().Get("site")
pinStatus := r.URL.Query().Get("pin") == "1"
if err := a.dataStore.SetPin(store.Locator{SiteID: siteID}, commentID, pinStatus); err != nil {
httpError(w, r, http.StatusBadRequest, err, "can't set pin status")
return
}
render.JSON(w, r, JSON{"comment_id": commentID, "site_id": siteID, "pin": pinStatus})
}
// GET /export?site=site-id
func (a *admin) exportCtrl(w http.ResponseWriter, r *http.Request) {
siteID := r.URL.Query().Get("site")
+29
View File
@@ -354,6 +354,35 @@ func (b BoltDB) List(locator Locator) (result []string, err error) {
return result, err
}
// SetPin pin/un-pin comment as special
func (b *BoltDB) SetPin(locator Locator, commentID string, status bool) error {
comment, err := b.Get(locator, commentID)
if err != nil {
return err
}
return b.Update(func(tx *bolt.Tx) error {
bucket := tx.Bucket([]byte(locator.URL))
if bucket == nil {
return errors.Errorf("no bucket %s in store", locator.URL)
}
comment.Pin = status
// serialize comment to json []byte for bolt and save
jdata, jerr := json.Marshal(&comment)
if jerr != nil {
return errors.Wrap(jerr, "can't marshal comment")
}
if err := bucket.Put([]byte(comment.ID), jdata); err != nil {
return errors.Wrapf(err, "failed to put key %s", comment.ID)
}
return nil
})
}
func (b *BoltDB) bucketForBlock(locator Locator, userID string) []byte {
return []byte(fmt.Sprintf("%s%s", blocksBucketPrefix, locator.SiteID))
}
+24
View File
@@ -141,6 +141,30 @@ func TestBoltDB_List(t *testing.T) {
assert.Equal(t, []string{"https://radio-t.com", "https://radio-t.com/2"}, res)
}
func TestBoltDB_Pin(t *testing.T) {
defer os.Remove(testDb)
b := prep(t)
res, err := b.Last(Locator{URL: "https://radio-t.com"}, 0)
t.Logf("%+v", res[0])
assert.Nil(t, err)
assert.Equal(t, 2, len(res))
assert.Equal(t, false, res[0].Pin)
err = b.SetPin(Locator{URL: "https://radio-t.com"}, res[0].ID, true)
assert.Nil(t, err)
c, err := b.Get(Locator{URL: "https://radio-t.com"}, res[0].ID)
assert.Nil(t, err)
assert.Equal(t, true, c.Pin)
err = b.SetPin(Locator{URL: "https://radio-t.com"}, res[0].ID, false)
assert.Nil(t, err)
c, err = b.Get(Locator{URL: "https://radio-t.com"}, res[0].ID)
assert.Nil(t, err)
assert.Equal(t, false, c.Pin)
}
// makes new boltdb, put two records
func prep(t *testing.T) *BoltDB {
os.Remove(testDb)
+3
View File
@@ -24,6 +24,7 @@ type Comment struct {
Score int `json:"score"`
Votes map[string]bool `json:"votes"`
Timestamp time.Time `json:"time"`
Pin bool `json:"pin"`
}
// Locator keeps site and url of the post
@@ -63,6 +64,8 @@ type Interface interface {
SetBlock(locator Locator, userID string, status bool) error
IsBlocked(locator Locator, userID string) bool
SetPin(locator Locator, commentID string, status bool) error
}
func makeCommentID() string {