package api import ( "log/slog" "net/http" ) // deviceTokenRequest is the JSON body for device registration. type deviceTokenRequest struct { Token string `json:"token"` Platform string `json:"platform"` // "ios" or "android" } // RegisterDevice saves a push notification token for the authenticated user. // POST /api/v1/devices func (h *Handlers) RegisterDevice(w http.ResponseWriter, r *http.Request) { did, ok := h.requireAuth(w, r) if !ok { return } var body deviceTokenRequest if err := decodeBody(r, &body); err != nil { writeError(w, http.StatusBadRequest, "invalid JSON") return } if body.Token == "" { writeError(w, http.StatusBadRequest, "token is required") return } if body.Platform != "ios" && body.Platform != "android" { writeError(w, http.StatusBadRequest, "platform must be 'ios' or 'android'") return } _, err := h.DB.ExecContext(r.Context(), ` INSERT INTO device_tokens (did, push_token, platform) VALUES (?, ?, ?) ON CONFLICT (did, push_token) DO UPDATE SET platform = excluded.platform, updated_at = CURRENT_TIMESTAMP `, did.String(), body.Token, body.Platform) if err != nil { slog.Warn("api: register device", "did", did, "err", err) writeError(w, http.StatusInternalServerError, "failed to register device") return } writeJSON(w, http.StatusCreated, map[string]string{"status": "registered"}) } // UnregisterDevice removes a push notification token. // DELETE /api/v1/devices/{token} func (h *Handlers) UnregisterDevice(w http.ResponseWriter, r *http.Request) { did, ok := h.requireAuth(w, r) if !ok { return } token := r.PathValue("token") if token == "" { writeError(w, http.StatusBadRequest, "missing token") return } _, err := h.DB.ExecContext(r.Context(), ` DELETE FROM device_tokens WHERE did = ? AND push_token = ? `, did.String(), token) if err != nil { slog.Warn("api: unregister device", "did", did, "err", err) writeError(w, http.StatusInternalServerError, "failed to unregister") return } writeJSON(w, http.StatusOK, map[string]string{"status": "removed"}) }