Enhance notification search functionality and update API documentation
- Added `search` and `q` query parameters to the `SearchForm` for improved notification searching capabilities. - Implemented `ResolvedSearch` method to prioritize search term resolution from the new parameters. - Updated `GetByUserID` repository method to support searching notifications by title and message using regex. - Enhanced logging in the `GetNotifications` service method to include search parameters. - Updated Swagger documentation to reflect the new search parameters for the notification API. This update improves the user experience by allowing more flexible and efficient searching of notifications.
This commit is contained in:
@@ -1,6 +1,8 @@
|
|||||||
package notification
|
package notification
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"strings"
|
||||||
|
|
||||||
"tm/pkg/response"
|
"tm/pkg/response"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -21,13 +23,26 @@ type NotificationRequest struct {
|
|||||||
|
|
||||||
// SearchForm represents the form for searching notifications
|
// SearchForm represents the form for searching notifications
|
||||||
type SearchForm struct {
|
type SearchForm struct {
|
||||||
Status string `query:"status" valid:"optional"`
|
Q *string `query:"q" valid:"optional"`
|
||||||
Method string `query:"method" valid:"optional"`
|
Search *string `query:"search" valid:"optional"`
|
||||||
EventType string `query:"event_type" valid:"optional"`
|
Status string `query:"status" valid:"optional"`
|
||||||
Type string `query:"type" valid:"optional"`
|
Method string `query:"method" valid:"optional"`
|
||||||
|
EventType string `query:"event_type" valid:"optional"`
|
||||||
|
Type string `query:"type" valid:"optional"`
|
||||||
Recipient []string `query:"recipient" json:"recipient" valid:"optional"`
|
Recipient []string `query:"recipient" json:"recipient" valid:"optional"`
|
||||||
Seen *bool `query:"seen" valid:"optional"`
|
Seen *bool `query:"seen" valid:"optional"`
|
||||||
Priority string `query:"priority" valid:"optional"`
|
Priority string `query:"priority" valid:"optional"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResolvedSearch returns the search term from either the search or q query parameter.
|
||||||
|
func (f *SearchForm) ResolvedSearch() string {
|
||||||
|
if f.Search != nil && strings.TrimSpace(*f.Search) != "" {
|
||||||
|
return strings.TrimSpace(*f.Search)
|
||||||
|
}
|
||||||
|
if f.Q != nil {
|
||||||
|
return strings.TrimSpace(*f.Q)
|
||||||
|
}
|
||||||
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
type NotificationListResponse struct {
|
type NotificationListResponse struct {
|
||||||
|
|||||||
@@ -58,6 +58,8 @@ func (h *NotificationHandler) Send(c echo.Context) error {
|
|||||||
// @Tags Admin-Notification
|
// @Tags Admin-Notification
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce 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 status query string false "Status filter"
|
||||||
// @Param method query string false "Method filter"
|
// @Param method query string false "Method filter"
|
||||||
// @Param event_type query string false "Event type filter"
|
// @Param event_type query string false "Event type filter"
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ package notification
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"tm/pkg/logger"
|
"tm/pkg/logger"
|
||||||
@@ -52,7 +54,7 @@ func (n *Notification) GetID() string {
|
|||||||
type Repository interface {
|
type Repository interface {
|
||||||
Create(ctx context.Context, notification *Notification) error
|
Create(ctx context.Context, notification *Notification) error
|
||||||
GetByID(ctx context.Context, id string) (*Notification, error)
|
GetByID(ctx context.Context, id string) (*Notification, error)
|
||||||
GetByUserID(ctx context.Context, userIDs []string, status string, seen *bool, priority, eventType, notificationType string, pagination *response.Pagination) (*orm.PaginatedResult[Notification], error)
|
GetByUserID(ctx context.Context, userIDs []string, search, status string, seen *bool, priority, eventType, notificationType string, pagination *response.Pagination) (*orm.PaginatedResult[Notification], error)
|
||||||
Update(ctx context.Context, notification *Notification) error
|
Update(ctx context.Context, notification *Notification) error
|
||||||
MarkAsSeen(ctx context.Context, notificationID, userID string) error
|
MarkAsSeen(ctx context.Context, notificationID, userID string) error
|
||||||
MarkAllAsSeen(ctx context.Context, userID string) error
|
MarkAllAsSeen(ctx context.Context, userID string) error
|
||||||
@@ -115,9 +117,17 @@ func (r *notificationRepository) GetByID(ctx context.Context, id string) (*Notif
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetByUserID retrieves notifications with optional user filters
|
// GetByUserID retrieves notifications with optional user filters
|
||||||
func (r *notificationRepository) GetByUserID(ctx context.Context, userIDs []string, status string, seen *bool, priority, eventType, notificationType string, pagination *response.Pagination) (*orm.PaginatedResult[Notification], error) {
|
func (r *notificationRepository) GetByUserID(ctx context.Context, userIDs []string, search, status string, seen *bool, priority, eventType, notificationType string, pagination *response.Pagination) (*orm.PaginatedResult[Notification], error) {
|
||||||
filter := bson.M{}
|
filter := bson.M{}
|
||||||
|
|
||||||
|
if q := strings.TrimSpace(search); q != "" {
|
||||||
|
pattern := regexp.QuoteMeta(q)
|
||||||
|
filter["$or"] = bson.A{
|
||||||
|
bson.M{"title": bson.M{"$regex": pattern, "$options": "i"}},
|
||||||
|
bson.M{"message": bson.M{"$regex": pattern, "$options": "i"}},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if len(userIDs) == 1 {
|
if len(userIDs) == 1 {
|
||||||
filter["user_id"] = userIDs[0]
|
filter["user_id"] = userIDs[0]
|
||||||
} else if len(userIDs) > 1 {
|
} else if len(userIDs) > 1 {
|
||||||
|
|||||||
@@ -183,7 +183,10 @@ func (s *notificationService) persistNotification(ctx context.Context, recipient
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *notificationService) GetNotifications(ctx context.Context, req *SearchForm, pagination *response.Pagination) (*NotificationListResponse, error) {
|
func (s *notificationService) GetNotifications(ctx context.Context, req *SearchForm, pagination *response.Pagination) (*NotificationListResponse, error) {
|
||||||
|
search := req.ResolvedSearch()
|
||||||
|
|
||||||
s.logger.Info("Getting notifications", map[string]interface{}{
|
s.logger.Info("Getting notifications", map[string]interface{}{
|
||||||
|
"search": search,
|
||||||
"status": req.Status,
|
"status": req.Status,
|
||||||
"method": req.Method,
|
"method": req.Method,
|
||||||
"event_type": req.EventType,
|
"event_type": req.EventType,
|
||||||
@@ -195,7 +198,7 @@ func (s *notificationService) GetNotifications(ctx context.Context, req *SearchF
|
|||||||
"offset": pagination.Offset,
|
"offset": pagination.Offset,
|
||||||
})
|
})
|
||||||
|
|
||||||
page, err := s.repository.GetByUserID(ctx, req.Recipient, req.Status, req.Seen, req.Priority, req.EventType, req.Type, pagination)
|
page, err := s.repository.GetByUserID(ctx, req.Recipient, search, req.Status, req.Seen, req.Priority, req.EventType, req.Type, pagination)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.logger.Error("Failed to get notifications", map[string]interface{}{
|
s.logger.Error("Failed to get notifications", map[string]interface{}{
|
||||||
"error": err.Error(),
|
"error": err.Error(),
|
||||||
|
|||||||
Reference in New Issue
Block a user