- Introduced new functionality for managing email attachments and drafts in the mail API. - Added handlers for listing, uploading, and downloading message attachments in `internal/api/mail/handlers_attachments.go`. - Implemented draft management endpoints for creating, updating, and deleting drafts in `internal/api/mail/handlers_drafts.go`. - Created new service methods for handling draft and attachment operations in `internal/api/mail/drafts.go` and `internal/api/mail/storage.go`. - Added validation and error handling for draft and attachment operations. - Included unit tests for draft and folder functionalities in `internal/api/mail/drafts_test.go` and `internal/api/mail/folders_test.go`. - Updated API routes to support new draft and attachment features, enhancing overall mail management capabilities.
87 lines
2.4 KiB
Go
87 lines
2.4 KiB
Go
package mail
|
|
|
|
import (
|
|
"net/http"
|
|
"time"
|
|
|
|
"github.com/ultisuite/ulti-backend/internal/api/apiresponse"
|
|
"github.com/ultisuite/ulti-backend/internal/api/apivalidate"
|
|
"github.com/ultisuite/ulti-backend/internal/api/middleware"
|
|
"github.com/ultisuite/ulti-backend/internal/api/query"
|
|
)
|
|
|
|
func (h *Handler) SearchMessages(w http.ResponseWriter, r *http.Request) {
|
|
claims := middleware.ClaimsFromContext(r.Context())
|
|
params, err := query.ParseListRequest(r)
|
|
if err != nil {
|
|
apivalidate.WriteQueryError(w, r, err)
|
|
return
|
|
}
|
|
|
|
filter, verr := parseMessageSearchFilter(r)
|
|
if verr != nil {
|
|
apivalidate.WriteValidationError(w, r, verr)
|
|
return
|
|
}
|
|
|
|
result, err := h.svc.SearchMessages(r.Context(), claims.Sub, filter, params)
|
|
if err != nil {
|
|
h.logger.Error("search messages", "error", err)
|
|
apivalidate.WriteInternal(w, r)
|
|
return
|
|
}
|
|
apiresponse.WriteJSON(w, http.StatusOK, result)
|
|
}
|
|
|
|
func parseMessageSearchFilter(r *http.Request) (MessageSearchFilter, *apivalidate.ValidationError) {
|
|
q := r.URL.Query()
|
|
filter := MessageSearchFilter{
|
|
Query: q.Get("q"),
|
|
Sender: q.Get("from"),
|
|
Label: q.Get("label"),
|
|
AccountID: q.Get("account_id"),
|
|
}
|
|
|
|
if raw := q.Get("date_from"); raw != "" {
|
|
t, err := time.Parse(time.RFC3339, raw)
|
|
if err != nil {
|
|
return filter, apivalidate.NewValidationError(apivalidate.FieldDetail{
|
|
Field: "date_from", Message: "invalid RFC3339 datetime",
|
|
})
|
|
}
|
|
filter.DateFrom = &t
|
|
}
|
|
if raw := q.Get("date_to"); raw != "" {
|
|
t, err := time.Parse(time.RFC3339, raw)
|
|
if err != nil {
|
|
return filter, apivalidate.NewValidationError(apivalidate.FieldDetail{
|
|
Field: "date_to", Message: "invalid RFC3339 datetime",
|
|
})
|
|
}
|
|
filter.DateTo = &t
|
|
}
|
|
if raw := q.Get("has_attachment"); raw != "" {
|
|
switch raw {
|
|
case "true", "1":
|
|
v := true
|
|
filter.HasAttachments = &v
|
|
case "false", "0":
|
|
v := false
|
|
filter.HasAttachments = &v
|
|
default:
|
|
return filter, apivalidate.NewValidationError(apivalidate.FieldDetail{
|
|
Field: "has_attachment", Message: "must be true or false",
|
|
})
|
|
}
|
|
}
|
|
|
|
if filter.Query == "" && filter.Sender == "" && filter.Label == "" &&
|
|
filter.AccountID == "" && filter.DateFrom == nil && filter.DateTo == nil &&
|
|
filter.HasAttachments == nil {
|
|
return filter, apivalidate.NewValidationError(apivalidate.FieldDetail{
|
|
Field: "q", Message: "at least one search filter required",
|
|
})
|
|
}
|
|
return filter, nil
|
|
}
|