package handler import ( "strconv" "strings" "github.com/Wei-Shaw/sub2api/internal/handler/dto" "github.com/Wei-Shaw/sub2api/internal/pkg/response" middleware2 "github.com/Wei-Shaw/sub2api/internal/server/middleware" "github.com/Wei-Shaw/sub2api/internal/service" "github.com/gin-gonic/gin" ) // AnnouncementHandler handles user announcement operations type AnnouncementHandler struct { announcementService *service.AnnouncementService } // NewAnnouncementHandler creates a new user announcement handler func NewAnnouncementHandler(announcementService *service.AnnouncementService) *AnnouncementHandler { return &AnnouncementHandler{ announcementService: announcementService, } } // List handles listing announcements visible to current user // GET /api/v1/announcements func (h *AnnouncementHandler) List(c *gin.Context) { subject, ok := middleware2.GetAuthSubjectFromContext(c) if !ok { response.Unauthorized(c, "User not found in context") return } unreadOnly := parseBoolQuery(c.Query("unread_only")) items, err := h.announcementService.ListForUser(c.Request.Context(), subject.UserID, unreadOnly) if err != nil { response.ErrorFrom(c, err) return } out := make([]dto.UserAnnouncement, 0, len(items)) for i := range items { out = append(out, *dto.UserAnnouncementFromService(&items[i])) } response.Success(c, out) } // MarkRead marks an announcement as read for current user // POST /api/v1/announcements/:id/read func (h *AnnouncementHandler) MarkRead(c *gin.Context) { subject, ok := middleware2.GetAuthSubjectFromContext(c) if !ok { response.Unauthorized(c, "User not found in context") return } announcementID, err := strconv.ParseInt(c.Param("id"), 10, 64) if err != nil || announcementID <= 0 { response.BadRequest(c, "Invalid announcement ID") return } if err := h.announcementService.MarkRead(c.Request.Context(), subject.UserID, announcementID); err != nil { response.ErrorFrom(c, err) return } response.Success(c, gin.H{"message": "ok"}) } func parseBoolQuery(v string) bool { switch strings.TrimSpace(strings.ToLower(v)) { case "1", "true", "yes", "y", "on": return true default: return false } }