fix: notification integration issues
This commit is contained in:
parent
ccdfc537c2
commit
6a06b399c7
|
|
@ -1,21 +1,71 @@
|
|||
-- name: CreateNotification :one
|
||||
INSERT INTO notifications (
|
||||
id, recipient_id, type, level, error_severity, reciever, is_read, delivery_status, delivery_channel, payload, priority, timestamp, metadata
|
||||
) VALUES (
|
||||
$1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13
|
||||
) RETURNING *;
|
||||
|
||||
id,
|
||||
recipient_id,
|
||||
type,
|
||||
level,
|
||||
error_severity,
|
||||
reciever,
|
||||
is_read,
|
||||
delivery_status,
|
||||
delivery_channel,
|
||||
payload,
|
||||
priority,
|
||||
timestamp,
|
||||
metadata
|
||||
)
|
||||
VALUES (
|
||||
$1,
|
||||
$2,
|
||||
$3,
|
||||
$4,
|
||||
$5,
|
||||
$6,
|
||||
$7,
|
||||
$8,
|
||||
$9,
|
||||
$10,
|
||||
$11,
|
||||
$12,
|
||||
$13
|
||||
)
|
||||
RETURNING *;
|
||||
-- name: GetNotification :one
|
||||
SELECT * FROM notifications WHERE id = $1 LIMIT 1;
|
||||
|
||||
SELECT *
|
||||
FROM notifications
|
||||
WHERE id = $1
|
||||
LIMIT 1;
|
||||
-- name: GetAllNotifications :many
|
||||
SELECT *
|
||||
FROM notifications
|
||||
ORDER BY timestamp DESC
|
||||
LIMIT $1 OFFSET $2;
|
||||
-- name: ListNotifications :many
|
||||
SELECT * FROM notifications WHERE recipient_id = $1 ORDER BY timestamp DESC LIMIT $2 OFFSET $3;
|
||||
|
||||
SELECT *
|
||||
FROM notifications
|
||||
WHERE recipient_id = $1
|
||||
ORDER BY timestamp DESC
|
||||
LIMIT $2 OFFSET $3;
|
||||
-- name: CountUnreadNotifications :one
|
||||
SELECT count(id)
|
||||
FROM notifications
|
||||
WHERE recipient_id = $1
|
||||
AND is_read = false;
|
||||
-- name: UpdateNotificationStatus :one
|
||||
UPDATE notifications SET delivery_status = $2, is_read = $3, metadata = $4 WHERE id = $1 RETURNING *;
|
||||
|
||||
UPDATE notifications
|
||||
SET delivery_status = $2,
|
||||
is_read = $3,
|
||||
metadata = $4
|
||||
WHERE id = $1
|
||||
RETURNING *;
|
||||
-- name: ListFailedNotifications :many
|
||||
SELECT * FROM notifications WHERE delivery_status = 'failed' AND timestamp < NOW() - INTERVAL '1 hour' ORDER BY timestamp ASC LIMIT $1;
|
||||
|
||||
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;
|
||||
SELECT recipient_id
|
||||
FROM notifications
|
||||
WHERE reciever = $1;
|
||||
|
|
@ -66,7 +66,7 @@ wHERE (
|
|||
company_id = $2
|
||||
OR $2 IS NULL
|
||||
)
|
||||
LIMIT $3 OFFSET $4;
|
||||
LIMIT sqlc.narg('limit') OFFSET sqlc.narg('offset');
|
||||
-- name: GetTotalUsers :one
|
||||
SELECT COUNT(*)
|
||||
FROM users
|
||||
|
|
@ -109,7 +109,6 @@ WHERE id = $7;
|
|||
UPDATE users
|
||||
SET company_id = $1
|
||||
WHERE id = $2;
|
||||
|
||||
-- name: SuspendUser :exec
|
||||
UPDATE users
|
||||
SET suspended = $1,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
// Code generated by sqlc. DO NOT EDIT.
|
||||
// versions:
|
||||
// sqlc v1.28.0
|
||||
|
|
|
|||
|
|
@ -11,12 +11,52 @@ import (
|
|||
"github.com/jackc/pgx/v5/pgtype"
|
||||
)
|
||||
|
||||
const CountUnreadNotifications = `-- name: CountUnreadNotifications :one
|
||||
SELECT count(id)
|
||||
FROM notifications
|
||||
WHERE recipient_id = $1
|
||||
AND is_read = false
|
||||
`
|
||||
|
||||
func (q *Queries) CountUnreadNotifications(ctx context.Context, recipientID int64) (int64, error) {
|
||||
row := q.db.QueryRow(ctx, CountUnreadNotifications, recipientID)
|
||||
var count int64
|
||||
err := row.Scan(&count)
|
||||
return count, err
|
||||
}
|
||||
|
||||
const CreateNotification = `-- name: CreateNotification :one
|
||||
INSERT INTO notifications (
|
||||
id, recipient_id, type, level, error_severity, reciever, is_read, delivery_status, delivery_channel, payload, priority, timestamp, metadata
|
||||
) VALUES (
|
||||
$1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13
|
||||
) RETURNING id, recipient_id, type, level, error_severity, reciever, is_read, delivery_status, delivery_channel, payload, priority, version, timestamp, metadata
|
||||
id,
|
||||
recipient_id,
|
||||
type,
|
||||
level,
|
||||
error_severity,
|
||||
reciever,
|
||||
is_read,
|
||||
delivery_status,
|
||||
delivery_channel,
|
||||
payload,
|
||||
priority,
|
||||
timestamp,
|
||||
metadata
|
||||
)
|
||||
VALUES (
|
||||
$1,
|
||||
$2,
|
||||
$3,
|
||||
$4,
|
||||
$5,
|
||||
$6,
|
||||
$7,
|
||||
$8,
|
||||
$9,
|
||||
$10,
|
||||
$11,
|
||||
$12,
|
||||
$13
|
||||
)
|
||||
RETURNING id, recipient_id, type, level, error_severity, reciever, is_read, delivery_status, delivery_channel, payload, priority, version, timestamp, metadata
|
||||
`
|
||||
|
||||
type CreateNotificationParams struct {
|
||||
|
|
@ -71,8 +111,58 @@ func (q *Queries) CreateNotification(ctx context.Context, arg CreateNotification
|
|||
return i, err
|
||||
}
|
||||
|
||||
const GetAllNotifications = `-- name: GetAllNotifications :many
|
||||
SELECT id, recipient_id, type, level, error_severity, reciever, is_read, delivery_status, delivery_channel, payload, priority, version, timestamp, metadata
|
||||
FROM notifications
|
||||
ORDER BY timestamp DESC
|
||||
LIMIT $1 OFFSET $2
|
||||
`
|
||||
|
||||
type GetAllNotificationsParams struct {
|
||||
Limit int32 `json:"limit"`
|
||||
Offset int32 `json:"offset"`
|
||||
}
|
||||
|
||||
func (q *Queries) GetAllNotifications(ctx context.Context, arg GetAllNotificationsParams) ([]Notification, error) {
|
||||
rows, err := q.db.Query(ctx, GetAllNotifications, arg.Limit, arg.Offset)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []Notification
|
||||
for rows.Next() {
|
||||
var i Notification
|
||||
if err := rows.Scan(
|
||||
&i.ID,
|
||||
&i.RecipientID,
|
||||
&i.Type,
|
||||
&i.Level,
|
||||
&i.ErrorSeverity,
|
||||
&i.Reciever,
|
||||
&i.IsRead,
|
||||
&i.DeliveryStatus,
|
||||
&i.DeliveryChannel,
|
||||
&i.Payload,
|
||||
&i.Priority,
|
||||
&i.Version,
|
||||
&i.Timestamp,
|
||||
&i.Metadata,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const GetNotification = `-- name: GetNotification :one
|
||||
SELECT id, recipient_id, type, level, error_severity, reciever, is_read, delivery_status, delivery_channel, payload, priority, version, timestamp, metadata FROM notifications WHERE id = $1 LIMIT 1
|
||||
SELECT id, recipient_id, type, level, error_severity, reciever, is_read, delivery_status, delivery_channel, payload, priority, version, timestamp, metadata
|
||||
FROM notifications
|
||||
WHERE id = $1
|
||||
LIMIT 1
|
||||
`
|
||||
|
||||
func (q *Queries) GetNotification(ctx context.Context, id string) (Notification, error) {
|
||||
|
|
@ -98,7 +188,12 @@ func (q *Queries) GetNotification(ctx context.Context, id string) (Notification,
|
|||
}
|
||||
|
||||
const ListFailedNotifications = `-- name: ListFailedNotifications :many
|
||||
SELECT id, recipient_id, type, level, error_severity, reciever, is_read, delivery_status, delivery_channel, payload, priority, version, timestamp, metadata FROM notifications WHERE delivery_status = 'failed' AND timestamp < NOW() - INTERVAL '1 hour' ORDER BY timestamp ASC LIMIT $1
|
||||
SELECT id, recipient_id, type, level, error_severity, reciever, is_read, delivery_status, delivery_channel, payload, priority, version, timestamp, metadata
|
||||
FROM notifications
|
||||
WHERE delivery_status = 'failed'
|
||||
AND timestamp < NOW() - INTERVAL '1 hour'
|
||||
ORDER BY timestamp ASC
|
||||
LIMIT $1
|
||||
`
|
||||
|
||||
func (q *Queries) ListFailedNotifications(ctx context.Context, limit int32) ([]Notification, error) {
|
||||
|
|
@ -137,7 +232,11 @@ func (q *Queries) ListFailedNotifications(ctx context.Context, limit int32) ([]N
|
|||
}
|
||||
|
||||
const ListNotifications = `-- name: ListNotifications :many
|
||||
SELECT id, recipient_id, type, level, error_severity, reciever, is_read, delivery_status, delivery_channel, payload, priority, version, timestamp, metadata FROM notifications WHERE recipient_id = $1 ORDER BY timestamp DESC LIMIT $2 OFFSET $3
|
||||
SELECT id, recipient_id, type, level, error_severity, reciever, is_read, delivery_status, delivery_channel, payload, priority, version, timestamp, metadata
|
||||
FROM notifications
|
||||
WHERE recipient_id = $1
|
||||
ORDER BY timestamp DESC
|
||||
LIMIT $2 OFFSET $3
|
||||
`
|
||||
|
||||
type ListNotificationsParams struct {
|
||||
|
|
@ -182,7 +281,9 @@ func (q *Queries) ListNotifications(ctx context.Context, arg ListNotificationsPa
|
|||
}
|
||||
|
||||
const ListRecipientIDsByReceiver = `-- name: ListRecipientIDsByReceiver :many
|
||||
SELECT recipient_id FROM notifications WHERE reciever = $1
|
||||
SELECT recipient_id
|
||||
FROM notifications
|
||||
WHERE reciever = $1
|
||||
`
|
||||
|
||||
func (q *Queries) ListRecipientIDsByReceiver(ctx context.Context, reciever string) ([]int64, error) {
|
||||
|
|
@ -206,7 +307,12 @@ func (q *Queries) ListRecipientIDsByReceiver(ctx context.Context, reciever strin
|
|||
}
|
||||
|
||||
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
|
||||
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
|
||||
`
|
||||
|
||||
type UpdateNotificationStatusParams struct {
|
||||
|
|
|
|||
|
|
@ -182,14 +182,14 @@ wHERE (
|
|||
company_id = $2
|
||||
OR $2 IS NULL
|
||||
)
|
||||
LIMIT $3 OFFSET $4
|
||||
LIMIT $4 OFFSET $3
|
||||
`
|
||||
|
||||
type GetAllUsersParams struct {
|
||||
Role string `json:"role"`
|
||||
CompanyID pgtype.Int8 `json:"company_id"`
|
||||
Limit int32 `json:"limit"`
|
||||
Offset int32 `json:"offset"`
|
||||
Offset pgtype.Int4 `json:"offset"`
|
||||
Limit pgtype.Int4 `json:"limit"`
|
||||
}
|
||||
|
||||
type GetAllUsersRow struct {
|
||||
|
|
@ -212,8 +212,8 @@ func (q *Queries) GetAllUsers(ctx context.Context, arg GetAllUsersParams) ([]Get
|
|||
rows, err := q.db.Query(ctx, GetAllUsers,
|
||||
arg.Role,
|
||||
arg.CompanyID,
|
||||
arg.Limit,
|
||||
arg.Offset,
|
||||
arg.Limit,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
|
|||
|
|
@ -9,6 +9,10 @@ type ValidInt64 struct {
|
|||
Value int64
|
||||
Valid bool
|
||||
}
|
||||
type ValidInt struct {
|
||||
Value int
|
||||
Valid bool
|
||||
}
|
||||
|
||||
type ValidString struct {
|
||||
Value string
|
||||
|
|
|
|||
|
|
@ -15,6 +15,8 @@ type NotificationRepository interface {
|
|||
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)
|
||||
CountUnreadNotifications(ctx context.Context, recipient_id int64) (int64, error)
|
||||
GetAllNotifications(ctx context.Context, limit, offset int) ([]domain.Notification, error)
|
||||
}
|
||||
|
||||
type Repository struct {
|
||||
|
|
@ -105,6 +107,24 @@ func (r *Repository) ListNotifications(ctx context.Context, recipientID int64, l
|
|||
return result, nil
|
||||
}
|
||||
|
||||
func (r *Repository) GetAllNotifications(ctx context.Context, limit, offset int) ([]domain.Notification, error) {
|
||||
|
||||
dbNotifications, err := r.store.queries.GetAllNotifications(ctx, dbgen.GetAllNotificationsParams{
|
||||
Limit: int32(limit),
|
||||
Offset: int32(offset),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var result []domain.Notification = make([]domain.Notification, 0, len(dbNotifications))
|
||||
for _, dbNotif := range dbNotifications {
|
||||
domainNotif := r.mapDBToDomain(&dbNotif)
|
||||
result = append(result, *domainNotif)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (r *Repository) ListFailedNotifications(ctx context.Context, limit int) ([]domain.Notification, error) {
|
||||
dbNotifications, err := r.store.queries.ListFailedNotifications(ctx, int32(limit))
|
||||
if err != nil {
|
||||
|
|
@ -177,3 +197,7 @@ func unmarshalPayload(data []byte) (domain.NotificationPayload, error) {
|
|||
}
|
||||
return payload, nil
|
||||
}
|
||||
|
||||
func (r *Repository) CountUnreadNotifications(ctx context.Context, recipient_id int64) (int64, error) {
|
||||
return r.store.queries.CountUnreadNotifications(ctx, recipient_id)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -90,8 +90,14 @@ func (s *Store) GetAllUsers(ctx context.Context, filter user.Filter) ([]domain.U
|
|||
Int64: filter.CompanyID.Value,
|
||||
Valid: filter.CompanyID.Valid,
|
||||
},
|
||||
Limit: int32(filter.PageSize),
|
||||
Offset: int32(filter.Page),
|
||||
Limit: pgtype.Int4{
|
||||
Int32: int32(filter.PageSize.Value),
|
||||
Valid: filter.PageSize.Valid,
|
||||
},
|
||||
Offset: pgtype.Int4{
|
||||
Int32: int32(filter.Page.Value),
|
||||
Valid: filter.Page.Valid,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
|
|
|
|||
|
|
@ -16,4 +16,6 @@ type NotificationStore interface {
|
|||
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
|
||||
CountUnreadNotifications(ctx context.Context, recipient_id int64) (int64, error)
|
||||
GetAllNotifications(ctx context.Context, limit, offset int) ([]domain.Notification, error)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -85,28 +85,31 @@ func (s *Service) SendNotification(ctx context.Context, notification *domain.Not
|
|||
return nil
|
||||
}
|
||||
|
||||
func (s *Service) MarkAsRead(ctx context.Context, notificationID string, recipientID int64) error {
|
||||
_, err := s.repo.UpdateNotificationStatus(ctx, notificationID, string(domain.DeliveryStatusSent), true, nil)
|
||||
if err != nil {
|
||||
s.logger.Error("[NotificationSvc.MarkAsRead] Failed to mark notification as read", "notificationID", notificationID, "recipientID", recipientID, "error", err)
|
||||
return err
|
||||
func (s *Service) MarkAsRead(ctx context.Context, notificationIDs []string, recipientID int64) error {
|
||||
for _, notificationID := range notificationIDs {
|
||||
_, err := s.repo.UpdateNotificationStatus(ctx, notificationID, string(domain.DeliveryStatusSent), true, nil)
|
||||
if err != nil {
|
||||
s.logger.Error("[NotificationSvc.MarkAsRead] Failed to mark notification as read", "notificationID", notificationID, "recipientID", recipientID, "error", err)
|
||||
return err
|
||||
}
|
||||
|
||||
// count, err := s.repo.CountUnreadNotifications(ctx, recipientID)
|
||||
// if err != nil {
|
||||
// s.logger.Error("[NotificationSvc.MarkAsRead] Failed to count unread notifications", "recipientID", recipientID, "error", err)
|
||||
// return err
|
||||
// }
|
||||
|
||||
// s.Hub.Broadcast <- map[string]interface{}{
|
||||
// "type": "COUNT_NOT_OPENED_NOTIFICATION",
|
||||
// "recipient_id": recipientID,
|
||||
// "payload": map[string]int{
|
||||
// "not_opened_notifications_count": int(count),
|
||||
// },
|
||||
// }
|
||||
|
||||
s.logger.Info("[NotificationSvc.MarkAsRead] Notification marked as read", "notificationID", notificationID, "recipientID", recipientID)
|
||||
}
|
||||
|
||||
// count, err := s.repo.CountUnreadNotifications(ctx, recipientID)
|
||||
// if err != nil {
|
||||
// s.logger.Error("[NotificationSvc.MarkAsRead] Failed to count unread notifications", "recipientID", recipientID, "error", err)
|
||||
// return err
|
||||
// }
|
||||
|
||||
// s.Hub.Broadcast <- map[string]interface{}{
|
||||
// "type": "COUNT_NOT_OPENED_NOTIFICATION",
|
||||
// "recipient_id": recipientID,
|
||||
// "payload": map[string]int{
|
||||
// "not_opened_notifications_count": int(count),
|
||||
// },
|
||||
// }
|
||||
|
||||
s.logger.Info("[NotificationSvc.MarkAsRead] Notification marked as read", "notificationID", notificationID, "recipientID", recipientID)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
@ -120,6 +123,16 @@ func (s *Service) ListNotifications(ctx context.Context, recipientID int64, limi
|
|||
return notifications, nil
|
||||
}
|
||||
|
||||
func (s *Service) GetAllNotifications(ctx context.Context, limit, offset int) ([]domain.Notification, error) {
|
||||
notifications, err := s.repo.GetAllNotifications(ctx, limit, offset)
|
||||
if err != nil {
|
||||
s.logger.Error("[NotificationSvc.ListNotifications] Failed to get all notifications")
|
||||
return nil, err
|
||||
}
|
||||
s.logger.Info("[NotificationSvc.ListNotifications] Successfully retrieved all notifications", "count", len(notifications))
|
||||
return notifications, nil
|
||||
}
|
||||
|
||||
func (s *Service) ConnectWebSocket(ctx context.Context, recipientID int64, c *websocket.Conn) error {
|
||||
s.addConnection(ctx, recipientID, c)
|
||||
s.logger.Info("[NotificationSvc.ConnectWebSocket] WebSocket connection established", "recipientID", recipientID)
|
||||
|
|
@ -267,3 +280,6 @@ func (s *Service) retryFailedNotifications() {
|
|||
}
|
||||
}
|
||||
|
||||
func (s *Service) CountUnreadNotifications(ctx context.Context, recipient_id int64) (int64, error) {
|
||||
return s.repo.CountUnreadNotifications(ctx, recipient_id)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,8 +46,8 @@ func (s *Service) DeleteUser(ctx context.Context, id int64) error {
|
|||
type Filter struct {
|
||||
Role string
|
||||
CompanyID domain.ValidInt64
|
||||
Page int
|
||||
PageSize int
|
||||
Page domain.ValidInt
|
||||
PageSize domain.ValidInt
|
||||
}
|
||||
type ValidRole struct {
|
||||
Value domain.Role
|
||||
|
|
|
|||
|
|
@ -124,14 +124,21 @@ type AdminRes struct {
|
|||
// @Failure 500 {object} response.APIResponse
|
||||
// @Router /admin [get]
|
||||
func (h *Handler) GetAllAdmins(c *fiber.Ctx) error {
|
||||
|
||||
filter := user.Filter{
|
||||
Role: string(domain.RoleAdmin),
|
||||
CompanyID: domain.ValidInt64{
|
||||
Value: int64(c.QueryInt("company_id")),
|
||||
Valid: true,
|
||||
},
|
||||
Page: c.QueryInt("page", 1) - 1,
|
||||
PageSize: c.QueryInt("page_size", 10),
|
||||
Page: domain.ValidInt{
|
||||
Value: c.QueryInt("page", 1) - 1,
|
||||
Valid: true,
|
||||
},
|
||||
PageSize: domain.ValidInt{
|
||||
Value: c.QueryInt("page_size", 10),
|
||||
Valid: true,
|
||||
},
|
||||
}
|
||||
valErrs, ok := h.validator.Validate(c, filter)
|
||||
if !ok {
|
||||
|
|
@ -171,6 +178,6 @@ func (h *Handler) GetAllAdmins(c *fiber.Ctx) error {
|
|||
}
|
||||
}
|
||||
|
||||
return response.WritePaginatedJSON(c, fiber.StatusOK, "Admins retrieved successfully", result, nil, filter.Page, int(total))
|
||||
return response.WritePaginatedJSON(c, fiber.StatusOK, "Admins retrieved successfully", result, nil, filter.Page.Value, int(total))
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -115,8 +115,14 @@ func (h *Handler) GetAllManagers(c *fiber.Ctx) error {
|
|||
Value: int64(c.QueryInt("company_id")),
|
||||
Valid: true,
|
||||
},
|
||||
Page: c.QueryInt("page", 1) - 1,
|
||||
PageSize: c.QueryInt("page_size", 10),
|
||||
Page: domain.ValidInt{
|
||||
Value: c.QueryInt("page", 1) - 1,
|
||||
Valid: true,
|
||||
},
|
||||
PageSize: domain.ValidInt{
|
||||
Value: c.QueryInt("page_size", 10),
|
||||
Valid: true,
|
||||
},
|
||||
}
|
||||
valErrs, ok := h.validator.Validate(c, filter)
|
||||
if !ok {
|
||||
|
|
@ -156,7 +162,7 @@ func (h *Handler) GetAllManagers(c *fiber.Ctx) error {
|
|||
}
|
||||
}
|
||||
|
||||
return response.WritePaginatedJSON(c, fiber.StatusOK, "Managers retrieved successfully", result, nil, filter.Page, int(total))
|
||||
return response.WritePaginatedJSON(c, fiber.StatusOK, "Managers retrieved successfully", result, nil, filter.Page.Value, int(total))
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,11 +3,13 @@ package handlers
|
|||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/user"
|
||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/ws"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/gofiber/fiber/v2/middleware/adaptor"
|
||||
|
|
@ -101,7 +103,7 @@ func (h *Handler) ConnectSocket(c *fiber.Ctx) error {
|
|||
|
||||
func (h *Handler) MarkNotificationAsRead(c *fiber.Ctx) error {
|
||||
type Request struct {
|
||||
NotificationID string `json:"notification_id" validate:"required"`
|
||||
NotificationIDs []string `json:"notification_ids" validate:"required"`
|
||||
}
|
||||
|
||||
var req Request
|
||||
|
|
@ -110,14 +112,15 @@ func (h *Handler) MarkNotificationAsRead(c *fiber.Ctx) error {
|
|||
return fiber.NewError(fiber.StatusBadRequest, "Invalid request body")
|
||||
}
|
||||
|
||||
userID, ok := c.Locals("userID").(int64)
|
||||
userID, ok := c.Locals("user_id").(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)
|
||||
fmt.Printf("Notification IDs: %v \n", req.NotificationIDs)
|
||||
if err := h.notificationSvc.MarkAsRead(context.Background(), req.NotificationIDs, userID); err != nil {
|
||||
h.logger.Error("Failed to mark notifications as read", "notificationID", req.NotificationIDs, "error", err)
|
||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to update notification status")
|
||||
}
|
||||
|
||||
|
|
@ -181,17 +184,21 @@ func (h *Handler) CreateAndSendNotification(c *fiber.Ctx) error {
|
|||
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)
|
||||
recipients, _, err := h.userSvc.GetAllUsers(context.Background(), user.Filter{
|
||||
Role: string(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")
|
||||
}
|
||||
|
||||
fmt.Printf("Number of Recipients %d \n", len(recipients))
|
||||
|
||||
notificationIDs := make([]string, 0, len(recipients))
|
||||
for _, recipientID := range recipients {
|
||||
for _, user := range recipients {
|
||||
notification := &domain.Notification{
|
||||
ID: "",
|
||||
RecipientID: recipientID,
|
||||
RecipientID: user.ID,
|
||||
Type: req.Type,
|
||||
Level: req.Level,
|
||||
ErrorSeverity: req.ErrorSeverity,
|
||||
|
|
@ -205,7 +212,7 @@ func (h *Handler) CreateAndSendNotification(c *fiber.Ctx) error {
|
|||
}
|
||||
|
||||
if err := h.notificationSvc.SendNotification(context.Background(), notification); err != nil {
|
||||
h.logger.Error("[NotificationSvc.CreateAndSendNotification] Failed to send bulk notification", "recipientID", recipientID, "error", err)
|
||||
h.logger.Error("[NotificationSvc.CreateAndSendNotification] Failed to send bulk notification", "UserID", user.ID, "error", err)
|
||||
continue
|
||||
}
|
||||
notificationIDs = append(notificationIDs, notification.ID)
|
||||
|
|
@ -258,8 +265,60 @@ func (h *Handler) GetNotifications(c *fiber.Ctx) error {
|
|||
"limit": limit,
|
||||
"offset": offset,
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
func (h *Handler) getAllRecipientIDs(ctx context.Context, receiver domain.NotificationRecieverSide) ([]int64, error) {
|
||||
return h.notificationSvc.ListRecipientIDs(ctx, receiver)
|
||||
}
|
||||
|
||||
func (h *Handler) CountUnreadNotifications(c *fiber.Ctx) error {
|
||||
|
||||
userID, ok := c.Locals("user_id").(int64)
|
||||
if !ok || userID == 0 {
|
||||
h.logger.Error("[NotificationSvc.GetNotifications] Invalid user ID in context")
|
||||
return fiber.NewError(fiber.StatusUnauthorized, "Invalid user identification")
|
||||
}
|
||||
|
||||
total, err := h.notificationSvc.CountUnreadNotifications(c.Context(), userID)
|
||||
|
||||
if err != nil {
|
||||
h.logger.Error("[NotificationSvc.CountUnreadNotifications] Failed to fetch unread notification count", "error", err)
|
||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to fetch notifications")
|
||||
}
|
||||
|
||||
return c.Status(fiber.StatusOK).JSON(fiber.Map{
|
||||
"unread": total,
|
||||
})
|
||||
}
|
||||
|
||||
func (h *Handler) GetAllNotifications(c *fiber.Ctx) error {
|
||||
limitStr := c.Query("limit", "10")
|
||||
pageStr := c.Query("page", "1")
|
||||
|
||||
// Convert limit and offset to integers
|
||||
limit, err := strconv.Atoi(limitStr)
|
||||
if err != nil || limit <= 0 {
|
||||
h.logger.Error("[NotificationSvc.GetNotifications] Invalid limit value", "error", err)
|
||||
return fiber.NewError(fiber.StatusBadRequest, "Invalid limit value")
|
||||
}
|
||||
page, err := strconv.Atoi(pageStr)
|
||||
if err != nil || page <= 0 {
|
||||
h.logger.Error("[NotificationSvc.GetNotifications] Invalid page value", "error", err)
|
||||
return fiber.NewError(fiber.StatusBadRequest, "Invalid page value")
|
||||
}
|
||||
|
||||
notifications, err := h.notificationSvc.GetAllNotifications(context.Background(), limit, ((page - 1) * limit))
|
||||
if err != nil {
|
||||
h.logger.Error("[NotificationSvc.GetNotifications] Failed to fetch notifications", "error", err)
|
||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to fetch notifications")
|
||||
}
|
||||
|
||||
return c.Status(fiber.StatusOK).JSON(fiber.Map{
|
||||
"notifications": notifications,
|
||||
"total_count": len(notifications),
|
||||
"limit": limit,
|
||||
"page": page,
|
||||
})
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -177,7 +177,9 @@ func (a *App) initAppRoutes() {
|
|||
// Notification Routes
|
||||
a.fiber.Get("/ws/connect", a.WebsocketAuthMiddleware, h.ConnectSocket)
|
||||
a.fiber.Get("/notifications", a.authMiddleware, h.GetNotifications)
|
||||
a.fiber.Post("/notifications/mark-as-read", h.MarkNotificationAsRead)
|
||||
a.fiber.Get("/notifications/all", a.authMiddleware, h.GetAllNotifications)
|
||||
a.fiber.Post("/notifications/mark-as-read", a.authMiddleware, h.MarkNotificationAsRead)
|
||||
a.fiber.Get("/notifications/unread", a.authMiddleware, h.CountUnreadNotifications)
|
||||
a.fiber.Post("/notifications/create", h.CreateAndSendNotification)
|
||||
|
||||
// Virtual Game Routes
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user