package notices import ( "encoding/json" "net/http" "time" "github.com/wangjia/pangolin/server/internal/apierr" "github.com/wangjia/pangolin/server/internal/auth" ) // listLimit 是 GET /v1/notices 单次返回的最大条数(合并广播+定向后按 published_at 倒序截断)。 const listLimit = 50 // Handler 承载 /v1/notices、/v1/notices/read 两个受保护端点。 type Handler struct { st *Store } func NewHandler(st *Store) *Handler { return &Handler{st: st} } // List handles GET /v1/notices: 返回该用户可见的通知(广播 ∪ 定向)与未读数。 func (h *Handler) List(w http.ResponseWriter, r *http.Request) { ctx := r.Context() uid, ok := auth.UserIDFromContext(ctx) if !ok { apierr.WriteJSON(w, http.StatusUnauthorized, apierr.ErrUnauthorized) return } items, unreadCount, err := h.st.ListForUser(ctx, uid, time.Now().UTC(), listLimit) if err != nil { apierr.WriteJSON(w, http.StatusInternalServerError, apierr.ErrInternal) return } if items == nil { items = []Notice{} } w.Header().Set("Content-Type", "application/json; charset=utf-8") _ = json.NewEncoder(w).Encode(map[string]any{ "notices": items, "unread_count": unreadCount, }) } // MarkRead handles POST /v1/notices/read: 把用户已读水位推进到当前时间。 func (h *Handler) MarkRead(w http.ResponseWriter, r *http.Request) { ctx := r.Context() uid, ok := auth.UserIDFromContext(ctx) if !ok { apierr.WriteJSON(w, http.StatusUnauthorized, apierr.ErrUnauthorized) return } if err := h.st.MarkRead(ctx, uid, time.Now().UTC()); err != nil { apierr.WriteJSON(w, http.StatusInternalServerError, apierr.ErrInternal) return } w.Header().Set("Content-Type", "application/json; charset=utf-8") _ = json.NewEncoder(w).Encode(map[string]any{"ok": true}) }