159 lines
4.2 KiB
Go
159 lines
4.2 KiB
Go
|
|
package handler
|
||
|
|
|
||
|
|
import (
|
||
|
|
"accounting-app/internal/models"
|
||
|
|
"accounting-app/internal/service"
|
||
|
|
"accounting-app/pkg/api"
|
||
|
|
"net/http"
|
||
|
|
"strconv"
|
||
|
|
|
||
|
|
"github.com/gin-gonic/gin"
|
||
|
|
)
|
||
|
|
|
||
|
|
type NotificationHandler struct {
|
||
|
|
service *service.NotificationService
|
||
|
|
}
|
||
|
|
|
||
|
|
func NewNotificationHandler(service *service.NotificationService) *NotificationHandler {
|
||
|
|
return &NotificationHandler{service: service}
|
||
|
|
}
|
||
|
|
|
||
|
|
// GetNotifications returns a list of notifications for the user
|
||
|
|
func (h *NotificationHandler) GetNotifications(c *gin.Context) {
|
||
|
|
userID, exists := c.Get("user_id")
|
||
|
|
if !exists {
|
||
|
|
api.Unauthorized(c, "User not authenticated")
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
|
||
|
|
limit, _ := strconv.Atoi(c.DefaultQuery("limit", "10"))
|
||
|
|
|
||
|
|
var isRead *bool
|
||
|
|
if val, ok := c.GetQuery("is_read"); ok {
|
||
|
|
parsedVal, err := strconv.ParseBool(val)
|
||
|
|
if err == nil {
|
||
|
|
isRead = &parsedVal
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
notifications, total, err := h.service.GetNotifications(userID.(uint), page, limit, isRead)
|
||
|
|
if err != nil {
|
||
|
|
api.Error(c, http.StatusInternalServerError, "FETCH_ERROR", "Failed to fetch notifications")
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
api.Success(c, gin.H{
|
||
|
|
"notifications": notifications,
|
||
|
|
"total": total,
|
||
|
|
"page": page,
|
||
|
|
"limit": limit,
|
||
|
|
})
|
||
|
|
}
|
||
|
|
|
||
|
|
// GetUnreadCount returns the number of unread notifications
|
||
|
|
func (h *NotificationHandler) GetUnreadCount(c *gin.Context) {
|
||
|
|
userID, exists := c.Get("user_id")
|
||
|
|
if !exists {
|
||
|
|
api.Unauthorized(c, "User not authenticated")
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
count, err := h.service.GetUnreadCount(userID.(uint))
|
||
|
|
if err != nil {
|
||
|
|
api.Error(c, http.StatusInternalServerError, "FETCH_ERROR", "Failed to count unread notifications")
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
api.Success(c, gin.H{
|
||
|
|
"count": count,
|
||
|
|
})
|
||
|
|
}
|
||
|
|
|
||
|
|
// MarkAsRead marks a specific notification as read
|
||
|
|
func (h *NotificationHandler) MarkAsRead(c *gin.Context) {
|
||
|
|
userID, exists := c.Get("user_id")
|
||
|
|
if !exists {
|
||
|
|
api.Unauthorized(c, "User not authenticated")
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
id, err := strconv.ParseUint(c.Param("id"), 10, 64)
|
||
|
|
if err != nil {
|
||
|
|
api.Error(c, http.StatusBadRequest, "INVALID_ID", "Invalid notification ID")
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
if err := h.service.MarkAsRead(uint(id), userID.(uint)); err != nil {
|
||
|
|
api.Error(c, http.StatusInternalServerError, "UPDATE_ERROR", "Failed to mark as read")
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
api.Success(c, gin.H{"message": "Marked as read"})
|
||
|
|
}
|
||
|
|
|
||
|
|
// MarkAllAsRead marks all notifications as read
|
||
|
|
func (h *NotificationHandler) MarkAllAsRead(c *gin.Context) {
|
||
|
|
userID, exists := c.Get("user_id")
|
||
|
|
if !exists {
|
||
|
|
api.Unauthorized(c, "User not authenticated")
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
if err := h.service.MarkAllAsRead(userID.(uint)); err != nil {
|
||
|
|
api.Error(c, http.StatusInternalServerError, "UPDATE_ERROR", "Failed to mark all as read")
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
api.Success(c, gin.H{"message": "All marked as read"})
|
||
|
|
}
|
||
|
|
|
||
|
|
// CreateNotificationRequest represents the request body for creating a notification (internal/admin use primarily)
|
||
|
|
type CreateNotificationRequest struct {
|
||
|
|
Title string `json:"title" binding:"required"`
|
||
|
|
Content string `json:"content" binding:"required"`
|
||
|
|
Type string `json:"type" binding:"required"`
|
||
|
|
Link string `json:"link"`
|
||
|
|
}
|
||
|
|
|
||
|
|
// CreateNotification creates a new notification (For testing/admin purposes)
|
||
|
|
func (h *NotificationHandler) CreateNotification(c *gin.Context) {
|
||
|
|
userID, exists := c.Get("user_id")
|
||
|
|
if !exists {
|
||
|
|
api.Unauthorized(c, "User not authenticated")
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
var req CreateNotificationRequest
|
||
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||
|
|
api.Error(c, http.StatusBadRequest, "INVALID_REQUEST", "Invalid request")
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
err := h.service.CreateNotification(
|
||
|
|
userID.(uint),
|
||
|
|
req.Title,
|
||
|
|
req.Content,
|
||
|
|
models.NotificationType(req.Type),
|
||
|
|
req.Link,
|
||
|
|
)
|
||
|
|
if err != nil {
|
||
|
|
api.Error(c, http.StatusInternalServerError, "CREATE_ERROR", "Failed to create notification")
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
api.Success(c, gin.H{"message": "Notification created"})
|
||
|
|
}
|
||
|
|
|
||
|
|
// RegisterRoutes registers the notification routes
|
||
|
|
func (h *NotificationHandler) RegisterRoutes(r *gin.RouterGroup) {
|
||
|
|
notifications := r.Group("/notifications")
|
||
|
|
{
|
||
|
|
notifications.GET("", h.GetNotifications)
|
||
|
|
notifications.GET("/unread-count", h.GetUnreadCount)
|
||
|
|
notifications.PUT("/:id/read", h.MarkAsRead)
|
||
|
|
notifications.PUT("/read-all", h.MarkAllAsRead)
|
||
|
|
notifications.POST("", h.CreateNotification) // Admin/Internal use
|
||
|
|
}
|
||
|
|
}
|