feat: admin side ntification creation handler added
This commit is contained in:
parent
9ffcac096f
commit
6b52d139d4
|
|
@ -16,3 +16,6 @@ UPDATE notifications SET delivery_status = $2, is_read = $3, metadata = $4 WHERE
|
|||
|
||||
-- name: ListFailedNotifications :many
|
||||
SELECT * FROM notifications WHERE delivery_status = 'failed' AND timestamp < NOW() - INTERVAL '1 hour' ORDER BY timestamp ASC LIMIT $1;
|
||||
|
||||
-- name: ListRecipientIDsByReceiver :many
|
||||
SELECT recipient_id FROM notifications WHERE reciever = $1;
|
||||
|
|
|
|||
|
|
@ -181,6 +181,30 @@ func (q *Queries) ListNotifications(ctx context.Context, arg ListNotificationsPa
|
|||
return items, nil
|
||||
}
|
||||
|
||||
const ListRecipientIDsByReceiver = `-- name: ListRecipientIDsByReceiver :many
|
||||
SELECT recipient_id FROM notifications WHERE reciever = $1
|
||||
`
|
||||
|
||||
func (q *Queries) ListRecipientIDsByReceiver(ctx context.Context, reciever string) ([]int64, error) {
|
||||
rows, err := q.db.Query(ctx, ListRecipientIDsByReceiver, reciever)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []int64
|
||||
for rows.Next() {
|
||||
var recipient_id int64
|
||||
if err := rows.Scan(&recipient_id); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, recipient_id)
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const UpdateNotificationStatus = `-- name: UpdateNotificationStatus :one
|
||||
UPDATE notifications SET delivery_status = $2, is_read = $3, metadata = $4 WHERE id = $1 RETURNING id, recipient_id, type, level, error_severity, reciever, is_read, delivery_status, delivery_channel, payload, priority, version, timestamp, metadata
|
||||
`
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ type NotificationRepository interface {
|
|||
UpdateNotificationStatus(ctx context.Context, id, status string, isRead bool, metadata []byte) (*domain.Notification, error)
|
||||
ListNotifications(ctx context.Context, recipientID int64, limit, offset int) ([]domain.Notification, error)
|
||||
ListFailedNotifications(ctx context.Context, limit int) ([]domain.Notification, error)
|
||||
ListRecipientIDs(ctx context.Context, receiver domain.NotificationRecieverSide) ([]int64, error)
|
||||
}
|
||||
|
||||
type Repository struct {
|
||||
|
|
@ -119,6 +120,10 @@ func (r *Repository) ListFailedNotifications(ctx context.Context, limit int) ([]
|
|||
return result, nil
|
||||
}
|
||||
|
||||
func (r *Repository) ListRecipientIDs(ctx context.Context, receiver domain.NotificationRecieverSide) ([]int64, error) {
|
||||
return r.store.queries.ListRecipientIDsByReceiver(ctx, string(receiver))
|
||||
}
|
||||
|
||||
func (r *Repository) mapDBToDomain(dbNotif *dbgen.Notification) *domain.Notification {
|
||||
var errorSeverity *domain.NotificationErrorSeverity
|
||||
if dbNotif.ErrorSeverity.Valid {
|
||||
|
|
|
|||
|
|
@ -15,4 +15,5 @@ type NotificationStore interface {
|
|||
DisconnectWebSocket(recipientID int64)
|
||||
SendSMS(ctx context.Context, recipientID int64, message string) error
|
||||
SendEmail(ctx context.Context, recipientID int64, subject, message string) error
|
||||
ListRecipientIDs(ctx context.Context, receiver domain.NotificationRecieverSide) ([]int64, error) // New method
|
||||
}
|
||||
|
|
|
|||
|
|
@ -153,6 +153,10 @@ func (s *Service) startWorker() {
|
|||
}
|
||||
}
|
||||
|
||||
func (s *Service) ListRecipientIDs(ctx context.Context, receiver domain.NotificationRecieverSide) ([]int64, error) {
|
||||
return s.repo.ListRecipientIDs(ctx, receiver)
|
||||
}
|
||||
|
||||
func (s *Service) handleNotification(notification *domain.Notification) {
|
||||
ctx := context.Background()
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,9 @@ package handlers
|
|||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
|
||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/gofiber/websocket/v2"
|
||||
)
|
||||
|
|
@ -74,3 +76,107 @@ func (h *Handler) MarkNotificationAsRead(c *fiber.Ctx) error {
|
|||
|
||||
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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ func (a *App) initAppRoutes() {
|
|||
|
||||
a.fiber.Get("/notifications/ws/connect/:recipientID", handler.ConnectSocket)
|
||||
a.fiber.Post("/notifications/mark-as-read", handler.MarkNotificationAsRead)
|
||||
a.fiber.Post("/notifications/create", handler.CreateAndSendNotification)
|
||||
}
|
||||
|
||||
///user/profile get
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user