add pin comment
This commit is contained in:
@@ -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_
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user