From f16f9fb5a9cc938ff1d0735e09fcdad4c451a9ef Mon Sep 17 00:00:00 2001 From: Mazyar Date: Thu, 11 Jun 2026 01:33:47 +0330 Subject: [PATCH] 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. --- internal/notification/form.go | 27 +++++++++++++++++++++------ internal/notification/handler.go | 2 ++ internal/notification/repository.go | 14 ++++++++++++-- internal/notification/service.go | 5 ++++- 4 files changed, 39 insertions(+), 9 deletions(-) diff --git a/internal/notification/form.go b/internal/notification/form.go index 7878db1..1a15eb5 100644 --- a/internal/notification/form.go +++ b/internal/notification/form.go @@ -1,6 +1,8 @@ package notification import ( + "strings" + "tm/pkg/response" ) @@ -21,13 +23,26 @@ type NotificationRequest struct { // SearchForm represents the form for searching notifications type SearchForm struct { - Status string `query:"status" valid:"optional"` - Method string `query:"method" valid:"optional"` - EventType string `query:"event_type" valid:"optional"` - Type string `query:"type" valid:"optional"` + Q *string `query:"q" valid:"optional"` + Search *string `query:"search" valid:"optional"` + Status string `query:"status" 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"` - Seen *bool `query:"seen" valid:"optional"` - Priority string `query:"priority" valid:"optional"` + Seen *bool `query:"seen" 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 { diff --git a/internal/notification/handler.go b/internal/notification/handler.go index 74922ae..73236f2 100644 --- a/internal/notification/handler.go +++ b/internal/notification/handler.go @@ -58,6 +58,8 @@ func (h *NotificationHandler) Send(c echo.Context) error { // @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" diff --git a/internal/notification/repository.go b/internal/notification/repository.go index 98f9c9f..dcb8ea4 100644 --- a/internal/notification/repository.go +++ b/internal/notification/repository.go @@ -3,6 +3,8 @@ package notification import ( "context" "errors" + "regexp" + "strings" "time" "tm/pkg/logger" @@ -52,7 +54,7 @@ func (n *Notification) GetID() string { type Repository interface { Create(ctx context.Context, notification *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 MarkAsSeen(ctx context.Context, notificationID, 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 -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{} + 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 { filter["user_id"] = userIDs[0] } else if len(userIDs) > 1 { diff --git a/internal/notification/service.go b/internal/notification/service.go index 208ce81..59eb593 100644 --- a/internal/notification/service.go +++ b/internal/notification/service.go @@ -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) { + search := req.ResolvedSearch() + s.logger.Info("Getting notifications", map[string]interface{}{ + "search": search, "status": req.Status, "method": req.Method, "event_type": req.EventType, @@ -195,7 +198,7 @@ func (s *notificationService) GetNotifications(ctx context.Context, req *SearchF "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 { s.logger.Error("Failed to get notifications", map[string]interface{}{ "error": err.Error(),