Expose active announcements to authenticated users, track read state, and feed active database announcements into /api/status with legacy fallback.
118 lines
2.5 KiB
Go
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
|
|
}
|