package query import ( "context" "strings" "time" "forge.cadoles.com/wpetit/fake-smtp/internal/model" "forge.cadoles.com/wpetit/fake-smtp/internal/storm" stormdb "github.com/asdine/storm/v3" "github.com/asdine/storm/v3/q" "github.com/pkg/errors" "gitlab.com/wpetit/goweb/cqrs" "gitlab.com/wpetit/goweb/middleware/container" ) type InboxSearch struct { To string From string Body string Subject string Headers map[string]string After time.Time Before time.Time } type GetInboxRequest struct { OrderBy string Limit int Skip int Reverse bool Search *InboxSearch } type InboxData struct { Emails []*model.Email } func HandleGetInbox(ctx context.Context, qry cqrs.Query) (interface{}, error) { req, ok := qry.Request().(*GetInboxRequest) if !ok { return nil, cqrs.ErrUnexpectedRequest } ctn, err := container.From(ctx) if err != nil { return nil, errors.Wrap(err, "could not retrieve service container") } db, err := storm.From(ctn) if err != nil { return nil, errors.Wrap(err, "could not retrieve storm service") } emails := make([]*model.Email, 0) var query stormdb.Query if req.Search != nil { matchers := make([]q.Matcher, 0) if req.Search.Body != "" { matchers = append(matchers, q.Or( q.Re("HTML", req.Search.Body), q.Re("Text", req.Search.Body), )) } if req.Search.Subject != "" { matchers = append(matchers, q.Re("Subject", req.Search.Subject)) } query = db.Select(matchers...) } else { query = db.Select() } if req.OrderBy != "" { query = query.OrderBy(req.OrderBy) } else { query = query.OrderBy("SentAt").Reverse() } if req.Reverse { query = query.Reverse() } if req.Limit != 0 { query = query.Limit(req.Limit) } if req.Skip != 0 { query = query.Limit(req.Skip) } if err := query.Find(&emails); err != nil { if err == storm.ErrNotFound { return &InboxData{emails}, nil } return nil, errors.Wrap(err, "could not retrieve emails") } if req.Search == nil { return &InboxData{emails}, nil } filtered := make([]*model.Email, 0, len(emails)) for _, eml := range emails { match := true if req.Search.To != "" { found := false for _, addr := range eml.To { if strings.Contains(addr.Name, req.Search.To) || strings.Contains(addr.Address, req.Search.To) { found = true break } } if !found { match = false } } if req.Search.From != "" { found := false for _, addr := range eml.From { if strings.Contains(addr.Name, req.Search.From) || strings.Contains(addr.Address, req.Search.From) { found = true break } } if !found { match = false } } if !req.Search.After.IsZero() && !eml.SentAt.After(req.Search.After) { match = false } if !req.Search.Before.IsZero() && !eml.SentAt.Before(req.Search.Before) { match = false } if req.Search.Headers != nil { found := false for searchKey, searchValue := range req.Search.Headers { for headerKey, headerValues := range eml.Headers { if searchKey != headerKey { continue } for _, hv := range headerValues { if strings.Contains(hv, searchValue) { found = true break } } if found { break } } if found { break } } if !found { match = false } } if match { filtered = append(filtered, eml) } } return &InboxData{filtered}, nil }