new-api/controller/announcement_user.go
zizi eec9f4dcae feat: add user announcement endpoints
Expose active announcements to authenticated users, track read state, and feed active database announcements into /api/status with legacy fallback.
2026-05-20 13:15:35 +08:00

118 lines
2.5 KiB
Go

package controller
import (
"errors"
"strconv"
"time"
"github.com/QuantumNous/new-api/common"
"github.com/QuantumNous/new-api/model"
"github.com/gin-gonic/gin"
"gorm.io/gorm"
)
type userAnnouncementResponse struct {
model.Announcement
IsRead bool `json:"is_read"`
}
func GetUserAnnouncements(c *gin.Context) {
userId := c.GetInt("id")
unreadOnly := c.Query("unread") == "true"
var announcements []model.Announcement
var err error
if unreadOnly {
announcements, err = model.GetUnreadAnnouncements(userId)
} else {
announcements, err = model.GetActiveAnnouncements()
}
if err != nil {
common.ApiError(c, err)
return
}
result := make([]userAnnouncementResponse, 0, len(announcements))
for _, announcement := range announcements {
isRead := false
if !unreadOnly {
isRead, err = model.IsAnnouncementRead(announcement.Id, userId)
if err != nil {
common.ApiError(c, err)
return
}
}
result = append(result, userAnnouncementResponse{
Announcement: announcement,
IsRead: isRead,
})
}
common.ApiSuccess(c, result)
}
func MarkAnnouncementRead(c *gin.Context) {
announcementId, err := strconv.Atoi(c.Param("id"))
if err != nil || announcementId <= 0 {
common.ApiErrorMsg(c, "无效的公告 ID")
return
}
announcement, err := model.GetAnnouncementByID(announcementId)
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
common.ApiErrorMsg(c, "公告不存在或不可见")
return
}
common.ApiError(c, err)
return
}
if !isAnnouncementVisible(announcement) {
common.ApiErrorMsg(c, "公告不存在或不可见")
return
}
userId := c.GetInt("id")
isRead, err := model.IsAnnouncementRead(announcementId, userId)
if err != nil {
common.ApiError(c, err)
return
}
if isRead {
common.ApiSuccess(c, nil)
return
}
read := &model.AnnouncementRead{
AnnouncementId: announcementId,
UserId: userId,
ReadAt: time.Now(),
}
if err := read.Insert(); err != nil {
isRead, checkErr := model.IsAnnouncementRead(announcementId, userId)
if checkErr == nil && isRead {
common.ApiSuccess(c, nil)
return
}
common.ApiError(c, err)
return
}
common.ApiSuccess(c, nil)
}
func isAnnouncementVisible(announcement *model.Announcement) bool {
if announcement.Status != announcementStatusActive {
return false
}
now := time.Now()
if announcement.StartsAt != nil && announcement.StartsAt.After(now) {
return false
}
if announcement.EndsAt != nil && announcement.EndsAt.Before(now) {
return false
}
return true
}