summaryrefslogtreecommitdiff
path: root/internal/api/push.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/api/push.go')
-rw-r--r--internal/api/push.go105
1 files changed, 105 insertions, 0 deletions
diff --git a/internal/api/push.go b/internal/api/push.go
new file mode 100644
index 0000000..6fd805a
--- /dev/null
+++ b/internal/api/push.go
@@ -0,0 +1,105 @@
+package api
+
+import (
+ "encoding/json"
+ "net/http"
+
+ "github.com/google/uuid"
+ "github.com/thepeterstone/claudomator/internal/storage"
+)
+
+// pushSubscriptionStore is the minimal interface needed by push handlers.
+type pushSubscriptionStore interface {
+ SavePushSubscription(sub storage.PushSubscription) error
+ DeletePushSubscription(endpoint string) error
+ ListPushSubscriptions() ([]storage.PushSubscription, error)
+}
+
+// SetVAPIDConfig configures VAPID keys and email for web push notifications.
+func (s *Server) SetVAPIDConfig(pub, priv, email string) {
+ s.vapidPublicKey = pub
+ s.vapidPrivateKey = priv
+ s.vapidEmail = email
+}
+
+// SetPushStore configures the push subscription store.
+func (s *Server) SetPushStore(store pushSubscriptionStore) {
+ s.pushStore = store
+}
+
+// SetDropsDir configures the file drop directory.
+func (s *Server) SetDropsDir(dir string) {
+ s.dropsDir = dir
+}
+
+// handleGetVAPIDKey returns the VAPID public key for client-side push subscription.
+func (s *Server) handleGetVAPIDKey(w http.ResponseWriter, r *http.Request) {
+ writeJSON(w, http.StatusOK, map[string]string{"public_key": s.vapidPublicKey})
+}
+
+// handlePushSubscribe saves a new push subscription.
+func (s *Server) handlePushSubscribe(w http.ResponseWriter, r *http.Request) {
+ var input struct {
+ Endpoint string `json:"endpoint"`
+ Keys struct {
+ P256DH string `json:"p256dh"`
+ Auth string `json:"auth"`
+ } `json:"keys"`
+ }
+ if err := json.NewDecoder(r.Body).Decode(&input); err != nil {
+ writeJSON(w, http.StatusBadRequest, map[string]string{"error": "invalid JSON: " + err.Error()})
+ return
+ }
+ if input.Endpoint == "" {
+ writeJSON(w, http.StatusBadRequest, map[string]string{"error": "endpoint is required"})
+ return
+ }
+ if input.Keys.P256DH == "" || input.Keys.Auth == "" {
+ writeJSON(w, http.StatusBadRequest, map[string]string{"error": "keys.p256dh and keys.auth are required"})
+ return
+ }
+
+ sub := storage.PushSubscription{
+ ID: uuid.New().String(),
+ Endpoint: input.Endpoint,
+ P256DHKey: input.Keys.P256DH,
+ AuthKey: input.Keys.Auth,
+ }
+
+ store := s.pushStore
+ if store == nil {
+ store = s.store
+ }
+
+ if err := store.SavePushSubscription(sub); err != nil {
+ writeJSON(w, http.StatusInternalServerError, map[string]string{"error": err.Error()})
+ return
+ }
+ writeJSON(w, http.StatusCreated, map[string]string{"id": sub.ID})
+}
+
+// handlePushUnsubscribe deletes a push subscription.
+func (s *Server) handlePushUnsubscribe(w http.ResponseWriter, r *http.Request) {
+ var input struct {
+ Endpoint string `json:"endpoint"`
+ }
+ if err := json.NewDecoder(r.Body).Decode(&input); err != nil {
+ writeJSON(w, http.StatusBadRequest, map[string]string{"error": "invalid JSON: " + err.Error()})
+ return
+ }
+ if input.Endpoint == "" {
+ writeJSON(w, http.StatusBadRequest, map[string]string{"error": "endpoint is required"})
+ return
+ }
+
+ store := s.pushStore
+ if store == nil {
+ store = s.store
+ }
+
+ if err := store.DeletePushSubscription(input.Endpoint); err != nil {
+ writeJSON(w, http.StatusInternalServerError, map[string]string{"error": err.Error()})
+ return
+ }
+ w.WriteHeader(http.StatusNoContent)
+}