From 91adb9f16b9fb5becab54bdcf7a6d25388e04979 Mon Sep 17 00:00:00 2001 From: Umputun Date: Thu, 15 Feb 2018 21:54:45 -0600 Subject: [PATCH] initial notifier with nop implementation --- README.md | 1 + app/main.go | 3 +++ app/notifier/notifier.go | 35 +++++++++++++++++++++++++++++++++++ app/rest/server.go | 33 ++++++++++++++++++++++++++++++--- 4 files changed, 69 insertions(+), 3 deletions(-) create mode 100644 app/notifier/notifier.go diff --git a/README.md b/README.md index dc52a514..80373b90 100644 --- a/README.md +++ b/README.md @@ -206,6 +206,7 @@ Sort can be `time` or `score`. Supported sort order with prefix -/+, i.e. `-time Auth []string `json:"auth_providers"` } ``` +- `PUT /api/v1/notify?site=site-id&url=post-url&action=1` - subscribe(action=1)/unsubscribe(0) comment notifications. _auth required_ ### Admin diff --git a/app/main.go b/app/main.go index 3cf7de51..f99fe741 100644 --- a/app/main.go +++ b/app/main.go @@ -7,6 +7,8 @@ import ( "os" "time" + "github.com/umputun/remark/app/notifier" + "github.com/gorilla/sessions" "github.com/hashicorp/logutils" "github.com/jessevdk/go-flags" @@ -114,6 +116,7 @@ func main() { AuthProviders: makeAuthProviders(sessionStore, avatarProxy), Cache: common.NewLoadingCache(4*time.Hour, 15*time.Minute, postFlushFn), AvatarProxy: avatarProxy, + Notifier: notifier.NoOperation{}, } if opts.DevMode { diff --git a/app/notifier/notifier.go b/app/notifier/notifier.go new file mode 100644 index 00000000..e435682c --- /dev/null +++ b/app/notifier/notifier.go @@ -0,0 +1,35 @@ +package notifier + +import ( + "log" + + "github.com/umputun/remark/app/store" +) + +// Interface defines notifier, sending messages triggered by topic/reply updates +type Interface interface { + Subscribe(locator store.Locator, user store.User) error + UnSubscribe(locator store.Locator, user store.User) error + OnUpdate(locator store.Locator) error +} + +// NoOperation implements Interface doing nothing but logging +type NoOperation struct{} + +// Subscribe is a fake, just loging attempt +func (n NoOperation) Subscribe(locator store.Locator, user store.User) error { + 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 { + 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 { + log.Printf("[DEBUG] update for %+v", locator) + return nil +} diff --git a/app/rest/server.go b/app/rest/server.go index d4f9e876..f83b44bd 100644 --- a/app/rest/server.go +++ b/app/rest/server.go @@ -22,6 +22,7 @@ import ( "gopkg.in/russross/blackfriday.v2" "github.com/umputun/remark/app/migrator" + "github.com/umputun/remark/app/notifier" "github.com/umputun/remark/app/rest/auth" "github.com/umputun/remark/app/rest/avatar" "github.com/umputun/remark/app/rest/common" @@ -38,8 +39,10 @@ type Server struct { SessionStore sessions.Store Exporter migrator.Exporter Cache common.LoadingCache - DevMode bool AvatarProxy *avatar.Proxy + Notifier notifier.Interface + + DevMode bool httpServer *http.Server mod admin @@ -104,7 +107,7 @@ 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) // admin routes, admin users only s.mod = admin{dataService: s.DataService, exporter: s.Exporter, cache: s.Cache} rauth.Mount("/admin", s.mod.routes()) @@ -167,8 +170,11 @@ func (s *Server) createCommentCtrl(w http.ResponseWriter, r *http.Request) { return } - s.Cache.Flush() // reset all caches + if err = s.Notifier.OnUpdate(comment.Locator); err != nil { + log.Printf("[WARN] can't send notify event for %+v, %s", comment.Locator, err) + } + s.Cache.Flush() // reset all caches render.Status(r, http.StatusCreated) render.JSON(w, r, JSON{"id": id, "locator": comment.Locator}) } @@ -410,6 +416,27 @@ func (s *Server) voteCtrl(w http.ResponseWriter, r *http.Request) { render.JSON(w, r, JSON{"id": comment.ID, "score": comment.Score}) } +// PUT /notify?site=siteID&url=post-url&action=1 - subscribe/unsubscribe to notification +func (s *Server) notifyCtrl(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 { + case "1": + err = s.Notifier.Subscribe(locator, user) + case "0": + err = s.Notifier.UnSubscribe(locator, user) + } + if err != nil { + common.SendErrorJSON(w, r, http.StatusBadRequest, err, "can't subscribe/unsubscribe for notifications") + return + } +} + // serves static files from /web func (s *Server) addFileServer(r chi.Router, path string, root http.FileSystem) { log.Printf("[INFO] run file server for %s", root)