183 lines
7.2 KiB
Go
183 lines
7.2 KiB
Go
package handlers
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
|
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
|
"github.com/gofiber/fiber/v2"
|
|
"github.com/gofiber/websocket/v2"
|
|
)
|
|
|
|
func (h *Handler) ConnectSocket(c *fiber.Ctx) error {
|
|
if !websocket.IsWebSocketUpgrade(c) {
|
|
h.logger.Warn("WebSocket upgrade required")
|
|
return fiber.ErrUpgradeRequired
|
|
}
|
|
|
|
userID, ok := c.Locals("userID").(int64)
|
|
if !ok || userID == 0 {
|
|
h.logger.Error("Invalid user ID in context")
|
|
return fiber.NewError(fiber.StatusUnauthorized, "invalid user identification")
|
|
}
|
|
|
|
c.Locals("allowed", true)
|
|
|
|
return websocket.New(func(conn *websocket.Conn) {
|
|
ctx := context.Background()
|
|
logger := h.logger.With("userID", userID, "remoteAddr", conn.RemoteAddr())
|
|
|
|
if err := h.notificationSvc.ConnectWebSocket(ctx, userID, conn); err != nil {
|
|
logger.Error("Failed to connect WebSocket", "error", err)
|
|
_ = conn.Close()
|
|
return
|
|
}
|
|
|
|
logger.Info("WebSocket connection established")
|
|
|
|
defer func() {
|
|
h.notificationSvc.DisconnectWebSocket(userID)
|
|
logger.Info("WebSocket connection closed")
|
|
_ = conn.Close()
|
|
}()
|
|
|
|
for {
|
|
if _, _, err := conn.ReadMessage(); err != nil {
|
|
if websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway, websocket.CloseAbnormalClosure) {
|
|
logger.Warn("WebSocket unexpected close", "error", err)
|
|
}
|
|
break
|
|
}
|
|
}
|
|
})(c)
|
|
}
|
|
|
|
func (h *Handler) MarkNotificationAsRead(c *fiber.Ctx) error {
|
|
type Request struct {
|
|
NotificationID string `json:"notification_id" validate:"required"`
|
|
}
|
|
|
|
var req Request
|
|
if err := c.BodyParser(&req); err != nil {
|
|
h.logger.Error("Failed to parse request body", "error", err)
|
|
return fiber.NewError(fiber.StatusBadRequest, "Invalid request body")
|
|
}
|
|
|
|
userID, ok := c.Locals("userID").(int64)
|
|
if !ok || userID == 0 {
|
|
h.logger.Error("Invalid user ID in context")
|
|
return fiber.NewError(fiber.StatusUnauthorized, "invalid user identification")
|
|
}
|
|
|
|
if err := h.notificationSvc.MarkAsRead(context.Background(), req.NotificationID, userID); err != nil {
|
|
h.logger.Error("Failed to mark notification as read", "notificationID", req.NotificationID, "error", err)
|
|
return fiber.NewError(fiber.StatusInternalServerError, "Failed to update notification status")
|
|
}
|
|
|
|
return c.Status(fiber.StatusOK).JSON(fiber.Map{"message": "Notification marked as read"})
|
|
}
|
|
|
|
func (h *Handler) CreateAndSendNotification(c *fiber.Ctx) error {
|
|
type Request struct {
|
|
RecipientID int64 `json:"recipient_id" validate:"required_if=DeliveryScheme single"`
|
|
Type domain.NotificationType `json:"type" validate:"required"`
|
|
Level domain.NotificationLevel `json:"level" validate:"required"`
|
|
ErrorSeverity *domain.NotificationErrorSeverity `json:"error_severity"`
|
|
Reciever domain.NotificationRecieverSide `json:"reciever" validate:"required"`
|
|
DeliveryScheme domain.NotificationDeliveryScheme `json:"delivery_scheme" validate:"required"`
|
|
DeliveryChannel domain.DeliveryChannel `json:"delivery_channel" validate:"required"`
|
|
Payload domain.NotificationPayload `json:"payload" validate:"required"`
|
|
Priority int `json:"priority"`
|
|
Metadata json.RawMessage `json:"metadata,omitempty"`
|
|
}
|
|
|
|
var req Request
|
|
if err := c.BodyParser(&req); err != nil {
|
|
h.logger.Error("[NotificationSvc.CreateAndSendNotification] Failed to parse request body", "error", err)
|
|
return fiber.NewError(fiber.StatusBadRequest, "Invalid request body")
|
|
}
|
|
|
|
userID, ok := c.Locals("userID").(int64)
|
|
if !ok || userID == 0 {
|
|
h.logger.Error("[NotificationSvc.CreateAndSendNotification] Invalid user ID in context")
|
|
return fiber.NewError(fiber.StatusUnauthorized, "Invalid user identification")
|
|
}
|
|
|
|
switch req.DeliveryScheme {
|
|
case domain.NotificationDeliverySchemeSingle:
|
|
if req.Reciever == domain.NotificationRecieverSideCustomer && req.RecipientID != userID {
|
|
h.logger.Warn("[NotificationSvc.CreateAndSendNotification] Unauthorized attempt to send notification", "userID", userID, "recipientID", req.RecipientID)
|
|
return fiber.NewError(fiber.StatusForbidden, "Unauthorized to send notification to this recipient")
|
|
}
|
|
|
|
notification := &domain.Notification{
|
|
ID: "",
|
|
RecipientID: req.RecipientID,
|
|
Type: req.Type,
|
|
Level: req.Level,
|
|
ErrorSeverity: req.ErrorSeverity,
|
|
Reciever: req.Reciever,
|
|
IsRead: false,
|
|
DeliveryStatus: domain.DeliveryStatusPending,
|
|
DeliveryChannel: req.DeliveryChannel,
|
|
Payload: req.Payload,
|
|
Priority: req.Priority,
|
|
Metadata: req.Metadata,
|
|
}
|
|
|
|
if err := h.notificationSvc.SendNotification(context.Background(), notification); err != nil {
|
|
h.logger.Error("[NotificationSvc.CreateAndSendNotification] Failed to send single notification", "recipientID", req.RecipientID, "error", err)
|
|
return fiber.NewError(fiber.StatusInternalServerError, "Failed to send notification")
|
|
}
|
|
|
|
h.logger.Info("[NotificationSvc.CreateAndSendNotification] Single notification sent successfully", "recipientID", req.RecipientID, "type", req.Type)
|
|
return c.Status(fiber.StatusCreated).JSON(fiber.Map{"message": "Single notification sent successfully", "notification_id": notification.ID})
|
|
|
|
case domain.NotificationDeliverySchemeBulk:
|
|
recipients, err := h.getAllRecipientIDs(context.Background(), req.Reciever)
|
|
if err != nil {
|
|
h.logger.Error("[NotificationSvc.CreateAndSendNotification] Failed to fetch recipients for bulk notification", "error", err)
|
|
return fiber.NewError(fiber.StatusInternalServerError, "Failed to fetch recipients")
|
|
}
|
|
|
|
notificationIDs := make([]string, 0, len(recipients))
|
|
for _, recipientID := range recipients {
|
|
notification := &domain.Notification{
|
|
ID: "",
|
|
RecipientID: recipientID,
|
|
Type: req.Type,
|
|
Level: req.Level,
|
|
ErrorSeverity: req.ErrorSeverity,
|
|
Reciever: req.Reciever,
|
|
IsRead: false,
|
|
DeliveryStatus: domain.DeliveryStatusPending,
|
|
DeliveryChannel: req.DeliveryChannel,
|
|
Payload: req.Payload,
|
|
Priority: req.Priority,
|
|
Metadata: req.Metadata,
|
|
}
|
|
|
|
if err := h.notificationSvc.SendNotification(context.Background(), notification); err != nil {
|
|
h.logger.Error("[NotificationSvc.CreateAndSendNotification] Failed to send bulk notification", "recipientID", recipientID, "error", err)
|
|
continue
|
|
}
|
|
notificationIDs = append(notificationIDs, notification.ID)
|
|
}
|
|
|
|
h.logger.Info("[NotificationSvc.CreateAndSendNotification] Bulk notification sent successfully", "recipient_count", len(recipients), "type", req.Type)
|
|
return c.Status(fiber.StatusCreated).JSON(fiber.Map{
|
|
"message": "Bulk notification sent successfully",
|
|
"recipient_count": len(recipients),
|
|
"notification_ids": notificationIDs,
|
|
})
|
|
|
|
default:
|
|
h.logger.Error("[NotificationSvc.CreateAndSendNotification] Invalid delivery scheme", "delivery_scheme", req.DeliveryScheme)
|
|
return fiber.NewError(fiber.StatusBadRequest, "Invalid delivery scheme")
|
|
}
|
|
}
|
|
|
|
func (h *Handler) getAllRecipientIDs(ctx context.Context, receiver domain.NotificationRecieverSide) ([]int64, error) {
|
|
return h.notificationSvc.ListRecipientIDs(ctx, receiver)
|
|
}
|