apskel-pos-backend/internal/service/notification_service.go
2026-05-10 10:57:38 +07:00

155 lines
6.1 KiB
Go

package service
import (
"context"
"math"
"apskel-pos-be/internal/constants"
"apskel-pos-be/internal/contract"
"apskel-pos-be/internal/models"
"apskel-pos-be/internal/processor"
"apskel-pos-be/internal/transformer"
"github.com/google/uuid"
)
type NotificationService interface {
Send(ctx context.Context, req *contract.SendNotificationRequest, createdBy uuid.UUID) *contract.Response
Broadcast(ctx context.Context, req *contract.BroadcastNotificationRequest, organizationID, createdBy uuid.UUID) *contract.Response
MarkAsRead(ctx context.Context, receiverID, userID uuid.UUID) *contract.Response
MarkAllAsRead(ctx context.Context, userID uuid.UUID) *contract.Response
DeleteForUser(ctx context.Context, receiverID, userID uuid.UUID) *contract.Response
ListForUser(ctx context.Context, req *contract.ListNotificationsRequest, userID uuid.UUID) *contract.Response
GetByID(ctx context.Context, id uuid.UUID) *contract.Response
}
type NotificationServiceImpl struct {
notificationProcessor processor.NotificationProcessor
}
func NewNotificationService(notificationProcessor processor.NotificationProcessor) *NotificationServiceImpl {
return &NotificationServiceImpl{
notificationProcessor: notificationProcessor,
}
}
func (s *NotificationServiceImpl) Send(ctx context.Context, req *contract.SendNotificationRequest, createdBy uuid.UUID) *contract.Response {
modelReq := &models.SendNotificationRequest{
Title: req.Title,
Body: req.Body,
Type: req.Type,
Category: req.Category,
Priority: req.Priority,
ImageURL: req.ImageURL,
ActionURL: req.ActionURL,
NotifiableType: req.NotifiableType,
NotifiableID: req.NotifiableID,
Data: req.Data,
ReceiverIDs: req.ReceiverIDs,
ScheduledAt: req.ScheduledAt,
ExpiredAt: req.ExpiredAt,
CreatedBy: &createdBy,
}
resp, err := s.notificationProcessor.Send(ctx, modelReq)
if err != nil {
errResp := contract.NewResponseError(constants.InternalServerErrorCode, constants.NotificationServiceEntity, err.Error())
return contract.BuildErrorResponse([]*contract.ResponseError{errResp})
}
return contract.BuildSuccessResponse(transformer.NotificationModelResponseToContract(resp))
}
func (s *NotificationServiceImpl) Broadcast(ctx context.Context, req *contract.BroadcastNotificationRequest, organizationID, createdBy uuid.UUID) *contract.Response {
modelReq := &models.BroadcastNotificationRequest{
Title: req.Title,
Body: req.Body,
Type: req.Type,
Category: req.Category,
Priority: req.Priority,
ImageURL: req.ImageURL,
ActionURL: req.ActionURL,
NotifiableType: req.NotifiableType,
NotifiableID: req.NotifiableID,
Data: req.Data,
OrganizationID: organizationID,
ScheduledAt: req.ScheduledAt,
ExpiredAt: req.ExpiredAt,
CreatedBy: &createdBy,
}
resp, err := s.notificationProcessor.Broadcast(ctx, modelReq)
if err != nil {
errResp := contract.NewResponseError(constants.InternalServerErrorCode, constants.NotificationServiceEntity, err.Error())
return contract.BuildErrorResponse([]*contract.ResponseError{errResp})
}
return contract.BuildSuccessResponse(transformer.NotificationModelResponseToContract(resp))
}
func (s *NotificationServiceImpl) MarkAsRead(ctx context.Context, receiverID, userID uuid.UUID) *contract.Response {
resp, err := s.notificationProcessor.MarkAsRead(ctx, receiverID, userID)
if err != nil {
errResp := contract.NewResponseError(constants.InternalServerErrorCode, constants.NotificationServiceEntity, err.Error())
return contract.BuildErrorResponse([]*contract.ResponseError{errResp})
}
return contract.BuildSuccessResponse(transformer.NotificationReceiverModelResponseToContract(resp))
}
func (s *NotificationServiceImpl) MarkAllAsRead(ctx context.Context, userID uuid.UUID) *contract.Response {
if err := s.notificationProcessor.MarkAllAsRead(ctx, userID); err != nil {
errResp := contract.NewResponseError(constants.InternalServerErrorCode, constants.NotificationServiceEntity, err.Error())
return contract.BuildErrorResponse([]*contract.ResponseError{errResp})
}
return contract.BuildSuccessResponse(map[string]interface{}{"message": "All notifications marked as read"})
}
func (s *NotificationServiceImpl) DeleteForUser(ctx context.Context, receiverID, userID uuid.UUID) *contract.Response {
if err := s.notificationProcessor.DeleteForUser(ctx, receiverID, userID); err != nil {
errResp := contract.NewResponseError(constants.InternalServerErrorCode, constants.NotificationServiceEntity, err.Error())
return contract.BuildErrorResponse([]*contract.ResponseError{errResp})
}
return contract.BuildSuccessResponse(map[string]interface{}{"message": "Notification deleted"})
}
func (s *NotificationServiceImpl) ListForUser(ctx context.Context, req *contract.ListNotificationsRequest, userID uuid.UUID) *contract.Response {
modelReq := &models.ListNotificationsRequest{
Page: req.Page,
Limit: req.Limit,
UserID: userID,
IsRead: req.IsRead,
}
receivers, total, unreadCount, err := s.notificationProcessor.ListForUser(ctx, modelReq)
if err != nil {
errResp := contract.NewResponseError(constants.InternalServerErrorCode, constants.NotificationServiceEntity, err.Error())
return contract.BuildErrorResponse([]*contract.ResponseError{errResp})
}
totalPages := int(math.Ceil(float64(total) / float64(req.Limit)))
response := contract.ListNotificationsResponse{
Notifications: transformer.NotificationReceiverModelResponsesToContracts(receivers),
TotalCount: total,
UnreadCount: unreadCount,
Page: req.Page,
Limit: req.Limit,
TotalPages: totalPages,
}
return contract.BuildSuccessResponse(response)
}
func (s *NotificationServiceImpl) GetByID(ctx context.Context, id uuid.UUID) *contract.Response {
resp, err := s.notificationProcessor.GetByID(ctx, id)
if err != nil {
errResp := contract.NewResponseError(constants.NotFoundErrorCode, constants.NotificationServiceEntity, err.Error())
return contract.BuildErrorResponse([]*contract.ResponseError{errResp})
}
return contract.BuildSuccessResponse(transformer.NotificationModelResponseToContract(resp))
}