- Introduce interfaces for all major services (JWT, PostAI, Comment, Message, Notification, QRCodeLogin, Upload, Vote, etc.) to support dependency inversion. - Move query parameters from `internal/dto` to a new `internal/query` package to separate request payloads from data transfer objects. - Refactor `internal/router` to use embedded `RouterDeps` for cleaner dependency management. - Decouple handlers from repositories by injecting services instead of direct repository access, ensuring proper layering. - Improve database initialization by moving it from `internal/model` to `internal/database`. - Optimize message decryption by implementing a more efficient `BatchDecrypt` method in `MessageEncryptor` using a worker pool. - Enhance error handling and security by implementing fail-fast checks for encryption key length during startup. - Clean up unused code, including the `avatar` package and several unused DTOs.
178 lines
4.5 KiB
Go
178 lines
4.5 KiB
Go
package handler
|
|
|
|
import (
|
|
"strconv"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
|
|
"with_you/internal/dto"
|
|
"with_you/internal/pkg/cursor"
|
|
"with_you/internal/pkg/response"
|
|
"with_you/internal/service"
|
|
)
|
|
|
|
// NotificationHandler 通知处理器
|
|
type NotificationHandler struct {
|
|
notificationService service.NotificationService
|
|
}
|
|
|
|
// NewNotificationHandler 创建通知处理器
|
|
func NewNotificationHandler(notificationService service.NotificationService) *NotificationHandler {
|
|
return &NotificationHandler{
|
|
notificationService: notificationService,
|
|
}
|
|
}
|
|
|
|
// GetNotifications 获取通知列表
|
|
func (h *NotificationHandler) GetNotifications(c *gin.Context) {
|
|
userID := c.GetString("user_id")
|
|
if userID == "" {
|
|
response.Unauthorized(c, "")
|
|
return
|
|
}
|
|
|
|
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
|
|
pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "20"))
|
|
unreadOnly := c.Query("unread_only") == "true"
|
|
|
|
notifications, total, err := h.notificationService.GetByUserID(c.Request.Context(), userID, page, pageSize, unreadOnly)
|
|
if err != nil {
|
|
response.InternalServerError(c, "failed to get notifications")
|
|
return
|
|
}
|
|
|
|
response.Paginated(c, notifications, total, page, pageSize)
|
|
}
|
|
|
|
// MarkAsRead 标记为已读
|
|
func (h *NotificationHandler) MarkAsRead(c *gin.Context) {
|
|
userID := c.GetString("user_id")
|
|
if userID == "" {
|
|
response.Unauthorized(c, "")
|
|
return
|
|
}
|
|
|
|
id := c.Param("id")
|
|
|
|
err := h.notificationService.MarkAsReadWithUserID(c.Request.Context(), id, userID)
|
|
if err != nil {
|
|
response.HandleError(c, err, "failed to mark as read")
|
|
return
|
|
}
|
|
|
|
response.SuccessWithMessage(c, "marked as read", nil)
|
|
}
|
|
|
|
// MarkAllAsRead 标记所有为已读
|
|
func (h *NotificationHandler) MarkAllAsRead(c *gin.Context) {
|
|
userID := c.GetString("user_id")
|
|
if userID == "" {
|
|
response.Unauthorized(c, "")
|
|
return
|
|
}
|
|
|
|
err := h.notificationService.MarkAllAsRead(c.Request.Context(), userID)
|
|
if err != nil {
|
|
response.InternalServerError(c, "failed to mark all as read")
|
|
return
|
|
}
|
|
|
|
response.SuccessWithMessage(c, "all marked as read", nil)
|
|
}
|
|
|
|
// GetUnreadCount 获取未读数量
|
|
func (h *NotificationHandler) GetUnreadCount(c *gin.Context) {
|
|
userID := c.GetString("user_id")
|
|
if userID == "" {
|
|
response.Unauthorized(c, "")
|
|
return
|
|
}
|
|
|
|
count, err := h.notificationService.GetUnreadCount(c.Request.Context(), userID)
|
|
if err != nil {
|
|
response.InternalServerError(c, "failed to get unread count")
|
|
return
|
|
}
|
|
|
|
response.Success(c, gin.H{"count": count})
|
|
}
|
|
|
|
// DeleteNotification 删除通知
|
|
func (h *NotificationHandler) DeleteNotification(c *gin.Context) {
|
|
userID := c.GetString("user_id")
|
|
if userID == "" {
|
|
response.Unauthorized(c, "")
|
|
return
|
|
}
|
|
|
|
id := c.Param("id")
|
|
|
|
err := h.notificationService.DeleteNotification(c.Request.Context(), id, userID)
|
|
if err != nil {
|
|
response.HandleError(c, err, "failed to delete notification")
|
|
return
|
|
}
|
|
|
|
response.Success(c, gin.H{"success": true})
|
|
}
|
|
|
|
// ClearAllNotifications 清空所有通知
|
|
func (h *NotificationHandler) ClearAllNotifications(c *gin.Context) {
|
|
userID := c.GetString("user_id")
|
|
if userID == "" {
|
|
response.Unauthorized(c, "")
|
|
return
|
|
}
|
|
|
|
err := h.notificationService.ClearAllNotifications(c.Request.Context(), userID)
|
|
if err != nil {
|
|
response.InternalServerError(c, "failed to clear notifications")
|
|
return
|
|
}
|
|
|
|
response.Success(c, gin.H{"success": true})
|
|
}
|
|
|
|
// GetNotificationsByCursor 游标分页获取通知列表
|
|
func (h *NotificationHandler) GetNotificationsByCursor(c *gin.Context) {
|
|
userID := c.GetString("user_id")
|
|
if userID == "" {
|
|
response.Unauthorized(c, "")
|
|
return
|
|
}
|
|
|
|
// 解析游标分页请求
|
|
req := h.parseCursorRequest(c)
|
|
|
|
unreadOnly := c.Query("unread_only") == "true"
|
|
|
|
// 调用游标分页服务
|
|
result, err := h.notificationService.GetNotificationsByCursor(c.Request.Context(), userID, unreadOnly, req)
|
|
if err != nil {
|
|
response.InternalServerError(c, "failed to get notifications")
|
|
return
|
|
}
|
|
|
|
// 转换为响应结构
|
|
notificationResponses := dto.ConvertNotificationsToResponse(result.Items)
|
|
|
|
// 构建游标分页响应
|
|
cursorResp := &dto.NotificationCursorPageResponse{
|
|
Items: notificationResponses,
|
|
NextCursor: result.NextCursor,
|
|
PrevCursor: result.PrevCursor,
|
|
HasMore: result.HasMore,
|
|
}
|
|
|
|
response.Success(c, cursorResp)
|
|
}
|
|
|
|
// parseCursorRequest 解析游标分页请求参数
|
|
func (h *NotificationHandler) parseCursorRequest(c *gin.Context) *cursor.PageRequest {
|
|
cursorStr := c.Query("cursor")
|
|
direction := cursor.Direction(c.DefaultQuery("direction", "forward"))
|
|
pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "20"))
|
|
|
|
return cursor.NewPageRequest(cursorStr, direction, pageSize)
|
|
}
|