ultisuite-backend/internal/api/mail/validate_drafts.go
R3D347HR4Y 95196f7777 Add mail attachment and draft management features
- 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.
2026-05-22 17:14:36 +02:00

93 lines
2.9 KiB
Go

package mail
import (
"encoding/json"
"strconv"
"strings"
"github.com/ultisuite/ulti-backend/internal/api/apivalidate"
)
type draftRequest struct {
AccountID string `json:"account_id"`
IdentityID string `json:"identity_id"`
To []string `json:"to"`
Cc []string `json:"cc"`
Bcc []string `json:"bcc"`
Subject string `json:"subject"`
BodyText string `json:"body_text"`
BodyHTML string `json:"body_html"`
InReplyTo string `json:"in_reply_to"`
Attachments any `json:"attachments"`
}
func validateDraftRecipients(req *draftRequest) []apivalidate.FieldDetail {
var details []apivalidate.FieldDetail
for i, addr := range req.To {
if d := validateRecipient(addr); d != nil {
d.Field = "to[" + strconv.Itoa(i) + "]"
details = append(details, *d)
}
}
for i, addr := range req.Cc {
if d := validateRecipient(addr); d != nil {
d.Field = "cc[" + strconv.Itoa(i) + "]"
details = append(details, *d)
}
}
for i, addr := range req.Bcc {
if d := validateRecipient(addr); d != nil {
d.Field = "bcc[" + strconv.Itoa(i) + "]"
details = append(details, *d)
}
}
return details
}
func validateDraftContent(req *draftRequest) []apivalidate.FieldDetail {
var details []apivalidate.FieldDetail
if len(req.Subject) > maxSubjectLen {
details = append(details, apivalidate.FieldDetail{Field: "subject", Message: "too long"})
}
if len(req.BodyText) > maxBodyField {
details = append(details, apivalidate.FieldDetail{Field: "body_text", Message: "too long"})
}
if len(req.BodyHTML) > maxBodyField {
details = append(details, apivalidate.FieldDetail{Field: "body_html", Message: "too long"})
}
if req.InReplyTo != "" && len(req.InReplyTo) > 998 {
details = append(details, apivalidate.FieldDetail{Field: "in_reply_to", Message: "too long"})
}
if req.Attachments != nil {
if b, err := json.Marshal(req.Attachments); err != nil {
details = append(details, apivalidate.FieldDetail{Field: "attachments", Message: "invalid"})
} else if len(b) > maxSendRequestBody {
details = append(details, apivalidate.FieldDetail{Field: "attachments", Message: "too large"})
}
}
return details
}
func validateCreateDraft(req *draftRequest) *apivalidate.ValidationError {
var details []apivalidate.FieldDetail
if strings.TrimSpace(req.AccountID) == "" {
details = append(details, apivalidate.FieldDetail{Field: "account_id", Message: "required"})
}
details = append(details, validateDraftRecipients(req)...)
details = append(details, validateDraftContent(req)...)
if len(details) == 0 {
return nil
}
return apivalidate.NewValidationError(details...)
}
func validateUpdateDraft(req *draftRequest) *apivalidate.ValidationError {
var details []apivalidate.FieldDetail
details = append(details, validateDraftRecipients(req)...)
details = append(details, validateDraftContent(req)...)
if len(details) == 0 {
return nil
}
return apivalidate.NewValidationError(details...)
}