fix: notification integration issues

This commit is contained in:
Samuel Tariku 2025-05-22 00:15:30 +03:00
parent ccdfc537c2
commit 6a06b399c7
16 changed files with 352 additions and 70 deletions

View File

@ -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;

View File

@ -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,

View File

@ -1,4 +1,3 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.28.0

View File

@ -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 {

View File

@ -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

View File

@ -9,6 +9,10 @@ type ValidInt64 struct {
Value int64
Valid bool
}
type ValidInt struct {
Value int
Valid bool
}
type ValidString struct {
Value string

View File

@ -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)
}

View File

@ -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

View File

@ -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)
}

View File

@ -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)
}

View File

@ -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

View File

@ -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))
}

View File

@ -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))
}

View File

@ -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,
})
}

View File

@ -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

View File

@ -46,11 +46,13 @@ swagger:
.PHONY: db-up
db-up:
@docker compose up -d postgres
@docker compose up -d postgres migrate
.PHONY: db-down
db-down:
@docker compose down
postgres:
@docker exec -it fortunebet-backend-postgres-1 psql -U root -d gh
.PHONY: sqlc-gen
sqlc-gen: