define and nop implementation for nofier.Status

This commit is contained in:
Umputun
2018-02-15 22:30:52 -06:00
parent 91adb9f16b
commit d73f539eab
5 changed files with 68 additions and 9 deletions
+1
View File
@@ -207,6 +207,7 @@ Sort can be `time` or `score`. Supported sort order with prefix -/+, i.e. `-time
}
```
- `PUT /api/v1/notify?site=site-id&url=post-url&action=1` - subscribe(action=1)/unsubscribe(0) comment notifications. _auth required_
- `GET /api/v1/notify?site=site-id&url=post-url` - get subscription status. _auth required_
### Admin
+1 -1
View File
@@ -116,7 +116,7 @@ func main() {
AuthProviders: makeAuthProviders(sessionStore, avatarProxy),
Cache: common.NewLoadingCache(4*time.Hour, 15*time.Minute, postFlushFn),
AvatarProxy: avatarProxy,
Notifier: notifier.NoOperation{},
Notifier: notifier.NewNoperation(),
}
if opts.DevMode {
+34 -4
View File
@@ -1,7 +1,9 @@
package notifier
import (
"fmt"
"log"
"sync"
"github.com/umputun/remark/app/store"
)
@@ -11,25 +13,53 @@ type Interface interface {
Subscribe(locator store.Locator, user store.User) error
UnSubscribe(locator store.Locator, user store.User) error
OnUpdate(locator store.Locator) error
Status(locator store.Locator, user store.User) (bool, error)
}
// NoOperation implements Interface doing nothing but logging
type NoOperation struct{}
type NoOperation struct {
sync.RWMutex
status map[string]struct{}
}
// NewNoperation makes NoOperation fake notifier
func NewNoperation() *NoOperation {
res := NoOperation{status: map[string]struct{}{}}
return &res
}
// Subscribe is a fake, just loging attempt
func (n NoOperation) Subscribe(locator store.Locator, user store.User) error {
func (n *NoOperation) Subscribe(locator store.Locator, user store.User) error {
n.Lock()
n.status[n.key(locator, user)] = struct{}{}
n.Unlock()
log.Printf("[DEBUG] user %+v subscribed to %+v", user, locator)
return nil
}
// UnSubscribe is a fake, just loging attempt
func (n NoOperation) UnSubscribe(locator store.Locator, user store.User) error {
func (n *NoOperation) UnSubscribe(locator store.Locator, user store.User) error {
n.Lock()
delete(n.status, n.key(locator, user))
n.Unlock()
log.Printf("[DEBUG] user %+v unsubscribed from %+v", user, locator)
return nil
}
// OnUpdate is a fake, just loging event
func (n NoOperation) OnUpdate(locator store.Locator) error {
func (n *NoOperation) OnUpdate(locator store.Locator) error {
log.Printf("[DEBUG] update for %+v", locator)
return nil
}
// Status returns from in-memory
func (n *NoOperation) Status(locator store.Locator, user store.User) (bool, error) {
n.RLock()
defer n.RUnlock()
_, found := n.status[n.key(locator, user)]
return found, nil
}
func (n *NoOperation) key(locator store.Locator, user store.User) string {
return fmt.Sprintf("%+v-%s", locator, user.ID)
}
+23 -4
View File
@@ -107,7 +107,8 @@ func (s *Server) Run(port int) {
rauth.Put("/comment/{id}", s.updateCommentCtrl)
rauth.Get("/user", s.userInfoCtrl)
rauth.Put("/vote/{id}", s.voteCtrl)
rauth.Put("/notify", s.notifyCtrl)
rauth.Put("/notify", s.notifyActionCtrl)
rauth.Get("/notify", s.notifyStatusCtrl)
// admin routes, admin users only
s.mod = admin{dataService: s.DataService, exporter: s.Exporter, cache: s.Cache}
rauth.Mount("/admin", s.mod.routes())
@@ -417,24 +418,42 @@ func (s *Server) voteCtrl(w http.ResponseWriter, r *http.Request) {
}
// PUT /notify?site=siteID&url=post-url&action=1 - subscribe/unsubscribe to notification
func (s *Server) notifyCtrl(w http.ResponseWriter, r *http.Request) {
func (s *Server) notifyActionCtrl(w http.ResponseWriter, r *http.Request) {
user, err := common.GetUserInfo(r)
if err != nil {
common.SendErrorJSON(w, r, http.StatusUnauthorized, err, "can't get user info")
return
}
locator := store.Locator{SiteID: r.URL.Query().Get("site"), URL: r.URL.Query().Get("url")}
action := r.URL.Query().Get("action")
switch action {
action := "unknown"
switch r.URL.Query().Get("action") {
case "1":
err = s.Notifier.Subscribe(locator, user)
action = "subscribe"
case "0":
err = s.Notifier.UnSubscribe(locator, user)
action = "unsubscribe"
}
if err != nil {
common.SendErrorJSON(w, r, http.StatusBadRequest, err, "can't subscribe/unsubscribe for notifications")
return
}
render.JSON(w, r, JSON{"locator": locator, "user": user.ID, "action": action})
}
// GET /notify?site=siteID&url=post-url - get notification status
func (s *Server) notifyStatusCtrl(w http.ResponseWriter, r *http.Request) {
user, err := common.GetUserInfo(r)
if err != nil {
common.SendErrorJSON(w, r, http.StatusUnauthorized, err, "can't get user info")
return
}
locator := store.Locator{SiteID: r.URL.Query().Get("site"), URL: r.URL.Query().Get("url")}
status := "not subscribed"
if st, err := s.Notifier.Status(locator, user); err == nil && st {
status = "subscribed"
}
render.JSON(w, r, JSON{"locator": locator, "user": user.ID, "status": status})
}
// serves static files from /web
+9
View File
@@ -67,3 +67,12 @@ GET {{host}}/api/v1/admin/blocked?site=remark
### delete comment by id
DELETE {{host}}/api/v1/admin/comment/3665976683?site=remark&url=https://radio-t.com/p/2017/12/16/podcast-576/
### subscribe
PUT {{host}}/api/v1/notify?site=remark&url=https://radio-t.com/p/2017/12/16/podcast-576/&action=1
### unsubscribe
PUT {{host}}/api/v1/notify?site=remark&url=https://radio-t.com/p/2017/12/16/podcast-576/&action=0
### subscribtion status
GET {{host}}/api/v1/notify?site=remark&url=https://radio-t.com/p/2017/12/16/podcast-576/