package notification import ( "context" "github.com/asaskevich/govalidator" "github.com/labstack/echo/v4" "tm/internal/customer" "tm/internal/user" "tm/pkg/response" ) // NotificationHandler handles HTTP requests for notification operations type NotificationHandler struct { service Service } // NewNotificationHandler creates a new notification handler func NewHandler(service Service) *NotificationHandler { return &NotificationHandler{ service: service, } } // CreateNotification creates a new notification // @Summary Create a new notification // @Description Create a new notification with the provided information // @Tags Admin-Notification // @Accept json // @Produce json // @Param notification body NotificationRequest true "Notification information" // @Success 201 {object} response.APIResponse "Notification created successfully" // @Failure 400 {object} response.APIResponse // @Failure 500 {object} response.APIResponse // @Security BearerAuth // @Router /admin/v1/notifications [post] func (h *NotificationHandler) Send(c echo.Context) error { var req NotificationRequest if err := c.Bind(&req); err != nil { return response.BadRequest(c, "Invalid request format", err.Error()) } // Validate request if valid, err := govalidator.ValidateStruct(req); !valid { return response.ValidationError(c, "Validation failed", err.Error()) } // Send notification go h.service.Send(context.Background(), &req) return response.Created(c, nil, "Notification created successfully") } // GetNotifications gets notifications // @Summary Get notifications // @Description Get notifications // @Tags Admin-Notification // @Accept json // @Produce json // @Param search query string false "Search query for title and message" // @Param q query string false "Search query for title and message (alias of search)" // @Param status query string false "Status filter" // @Param method query string false "Method filter" // @Param event_type query string false "Event type filter" // @Param type query string false "Type filter" // @Param recipient query string false "Recipient filter" // @Param user_id query string false "User ID filter" // @Param seen query bool false "Seen filter" // @Param priority query string false "Priority filter" // @Param limit query int false "Limit results" // @Param offset query int false "Offset results" // @Param sort_by query string false "Sort field" // @Param sort_order query string false "Sort order" // @Success 200 {object} response.APIResponse{data=NotificationListResponse} // @Failure 401 {object} response.APIResponse // @Failure 403 {object} response.APIResponse // @Failure 400 {object} response.APIResponse // @Failure 500 {object} response.APIResponse // @Security BearerAuth // @Router /admin/v1/notifications [get] func (h *NotificationHandler) GetNotifications(c echo.Context) error { form, err := response.Parse[SearchForm](c) if err != nil { return response.BadRequest(c, "Invalid request format", err.Error()) } // Validate form if _, err := govalidator.ValidateStruct(form); err != nil { return response.ValidationError(c, err.Error(), "") } pagination, err := response.NewPagination(c) if err != nil { return response.PaginationBadRequest(c, err) } notifications, err := h.service.GetNotifications(c.Request().Context(), form, pagination) if err != nil { if response.IsListPaginationError(err) { return response.PaginationBadRequest(c, err) } return response.InternalServerError(c, "Failed to get notifications") } return response.SuccessWithMeta(c, notifications.Notifications, notifications.Meta, "Notifications retrieved successfully") } // MyAdminNotifications gets notifications for the admin // @Summary Get notifications for the admin // @Description Get notifications for the admin // @Tags Admin-Notification // @Accept json // @Produce json // @Param status query string false "Status filter" // @Param method query string false "Method filter" // @Param event_type query string false "Event type filter" // @Param type query string false "Type filter" // @Param recipient query string false "Recipient filter" // @Param seen query bool false "Seen filter" // @Param priority query string false "Priority filter" // @Param limit query int false "Limit results" // @Param offset query int false "Offset results" // @Param sort_by query string false "Sort field" // @Param sort_order query string false "Sort order" // @Success 200 {object} response.APIResponse{data=NotificationListResponse} // @Failure 401 {object} response.APIResponse // @Failure 403 {object} response.APIResponse // @Failure 400 {object} response.APIResponse // @Failure 500 {object} response.APIResponse // @Security BearerAuth // @Router /admin/v1/notifications/my [get] func (h *NotificationHandler) AdminNotifications(c echo.Context) error { userID, err := user.GetUserIDFromContext(c) if err != nil { return response.BadRequest(c, "User ID required", "User must be associated with a user") } form, err := response.Parse[SearchForm](c) if err != nil { return response.BadRequest(c, "Invalid request format", err.Error()) } // Validate form if _, err := govalidator.ValidateStruct(form); err != nil { return response.ValidationError(c, err.Error(), "") } form.Recipient = []string{userID} form.Status = "sent" form.EventType = EventTypeInApp form.Method = "" pagination, err := response.NewPagination(c) if err != nil { return response.PaginationBadRequest(c, err) } notifications, err := h.service.GetNotifications(c.Request().Context(), form, pagination) if err != nil { if response.IsListPaginationError(err) { return response.PaginationBadRequest(c, err) } return response.InternalServerError(c, "Failed to get notifications") } return response.SuccessWithMeta(c, notifications.Notifications, notifications.Meta, "Notifications retrieved successfully") } // MarkSeen marks a notification as seen // @Summary Mark a notification as seen // @Description Mark a notification as seen // @Tags Admin-Notification // @Accept json // @Produce json // @Param id path string true "Notification ID" // @Success 200 {object} response.APIResponse // @Failure 400 {object} response.APIResponse // @Failure 500 {object} response.APIResponse // @Security BearerAuth // @Router /admin/v1/notifications/mark-seen/{id} [get] func (h *NotificationHandler) MarkSeen(c echo.Context) error { notificationID := c.Param("id") userID, err := user.GetUserIDFromContext(c) if err != nil { return response.BadRequest(c, "User ID required", "User must be associated with a user") } // Mark notification as seen err = h.service.MarkSeen(c.Request().Context(), notificationID, userID) if err != nil { return response.InternalServerError(c, "Failed to mark notification as seen") } return response.Success(c, nil, "Notification marked as seen successfully") } // ViewNotification gets a single notification by ID // @Summary Get notification details // @Description Get detailed information about a specific notification // @Tags Admin-Notification // @Accept json // @Produce json // @Param id path string true "Notification ID" // @Success 200 {object} response.APIResponse{data=NotificationResponse} // @Failure 400 {object} response.APIResponse // @Failure 404 {object} response.APIResponse // @Failure 500 {object} response.APIResponse // @Security BearerAuth // @Router /admin/v1/notifications/view/{id} [get] func (h *NotificationHandler) ViewNotification(c echo.Context) error { notificationID := c.Param("id") if notificationID == "" { return response.BadRequest(c, "notification ID is required", "Notification ID must be provided") } // Get notification details notification, err := h.service.GetNotification(c.Request().Context(), notificationID) if err != nil { return response.InternalServerError(c, "Failed to get notification details") } return response.Success(c, notification, "Notification details retrieved successfully") } // **************************** PUBLIC ENDPOINTS **************************** // MyNotifications gets notifications for the user // @Summary Get notifications for the user // @Description Get notifications for the user // @Tags Notification // @Accept json // @Produce json // @Param status query string false "Status filter" // @Param method query string false "Method filter" // @Param event_type query string false "Event type filter" // @Param type query string false "Type filter" // @Param recipient query string false "Recipient filter" // @Param seen query bool false "Seen filter" // @Param priority query string false "Priority filter" // @Param limit query int false "Limit results" // @Param offset query int false "Offset results" // @Param sort_by query string false "Sort field" // @Param sort_order query string false "Sort order" // @Success 200 {object} response.APIResponse{data=NotificationListResponse} // @Failure 401 {object} response.APIResponse // @Failure 403 {object} response.APIResponse // @Failure 400 {object} response.APIResponse // @Failure 500 {object} response.APIResponse // @Security BearerAuth // @Router /api/v1/notifications [get] func (h *NotificationHandler) CustomerNotifications(c echo.Context) error { userID, err := customer.GetCustomerIDFromContext(c) if err != nil { return response.BadRequest(c, "User ID required", "User must be associated with a user") } form, err := response.Parse[SearchForm](c) if err != nil { return response.BadRequest(c, "Invalid request format", err.Error()) } // Validate form if _, err := govalidator.ValidateStruct(form); err != nil { return response.ValidationError(c, err.Error(), "") } form.Recipient = []string{userID} form.Status = "sent" form.EventType = EventTypeInApp form.Method = "" pagination, err := response.NewPagination(c) if err != nil { return response.PaginationBadRequest(c, err) } notifications, err := h.service.GetNotifications(c.Request().Context(), form, pagination) if err != nil { if response.IsListPaginationError(err) { return response.PaginationBadRequest(c, err) } c.Logger().Error("GetNotifications failed", map[string]interface{}{ "error": err.Error(), "status": form.Status, "priority": form.Priority, "eventType": form.EventType, "recipient": form.Recipient, "limit": pagination.Limit, "offset": pagination.Offset, "page": (pagination.Offset / pagination.Limit) + 1, }) return response.InternalServerError(c, "Failed to get notifications") } return response.SuccessWithMeta(c, notifications.Notifications, notifications.Meta, "Notifications retrieved successfully") } // MarkSeen marks a notification as seen // @Summary Mark a notification as seen // @Description Mark a notification as seen // @Tags Notification // @Accept json // @Produce json // @Param id path string true "Notification ID" // @Success 200 {object} response.APIResponse // @Failure 400 {object} response.APIResponse // @Failure 500 {object} response.APIResponse // @Security BearerAuth // @Router /api/v1/notifications/mark/{id} [get] func (h *NotificationHandler) PublicMarkSeen(c echo.Context) error { notificationID := c.Param("id") userID, err := customer.GetCustomerIDFromContext(c) if err != nil { return response.BadRequest(c, "User ID required", "User must be associated with a user") } // Mark notification as seen err = h.service.MarkSeen(c.Request().Context(), notificationID, userID) if err != nil { return response.InternalServerError(c, "Failed to mark notification as seen") } return response.Success(c, nil, "Notification marked as seen successfully") } // AllMarkSeen marks all notifications as seen for a user // @Summary Mark all notifications as seen for a user // @Description Mark all notifications as seen for a user // @Tags Notification // @Accept json // @Produce json // @Param user_id path string true "User ID" // @Success 200 {object} response.APIResponse // @Failure 400 {object} response.APIResponse // @Failure 500 {object} response.APIResponse // @Security BearerAuth // @Router /api/v1/notifications/mark [get] func (h *NotificationHandler) PublicAllMarkSeen(c echo.Context) error { userID, err := customer.GetCustomerIDFromContext(c) if err != nil { return response.BadRequest(c, "user ID is required", "User ID must be provided") } // Mark all notifications as seen err = h.service.AllMarkSeen(c.Request().Context(), userID) if err != nil { return response.InternalServerError(c, "Failed to mark all notifications as seen") } return response.Success(c, nil, "All notifications marked as seen successfully") } // ViewNotification gets a single notification by ID // @Summary Get notification details // @Description Get detailed information about a specific notification // @Tags Notification // @Accept json // @Produce json // @Param id path string true "Notification ID" // @Success 200 {object} response.APIResponse{data=DetailedNotificationResponse} // @Failure 400 {object} response.APIResponse // @Failure 404 {object} response.APIResponse // @Failure 500 {object} response.APIResponse // @Security BearerAuth // @Router /api/v1/notifications/view/{id} [get] func (h *NotificationHandler) PublicViewNotification(c echo.Context) error { notificationID := c.Param("id") if notificationID == "" { return response.BadRequest(c, "notification ID is required", "Notification ID must be provided") } // Get notification details notification, err := h.service.GetNotification(c.Request().Context(), notificationID) if err != nil { return response.InternalServerError(c, "Failed to get notification details") } return response.Success(c, notification, "Notification details retrieved successfully") }