- 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.
109 lines
2.9 KiB
Go
109 lines
2.9 KiB
Go
package mail
|
|
|
|
import (
|
|
"context"
|
|
|
|
"github.com/ultisuite/ulti-backend/internal/api/query"
|
|
"github.com/ultisuite/ulti-backend/internal/securityaudit"
|
|
)
|
|
|
|
type UserLabelsList struct {
|
|
Labels []map[string]any `json:"labels"`
|
|
Pagination query.PaginationMeta `json:"pagination,omitempty"`
|
|
}
|
|
|
|
func (s *Service) ListUserLabels(ctx context.Context, externalID string, params query.ListParams) (UserLabelsList, error) {
|
|
var total int64
|
|
err := s.db.QueryRow(ctx, `
|
|
SELECT COUNT(*) FROM mail_user_labels
|
|
WHERE user_id = (SELECT id FROM users WHERE external_id = $1)
|
|
`, externalID).Scan(&total)
|
|
if err != nil {
|
|
return UserLabelsList{}, err
|
|
}
|
|
|
|
rows, err := s.db.Query(ctx, `
|
|
SELECT id, name, color, created_at
|
|
FROM mail_user_labels
|
|
WHERE user_id = (SELECT id FROM users WHERE external_id = $1)
|
|
ORDER BY name ASC
|
|
LIMIT $2 OFFSET $3
|
|
`, externalID, params.Limit(), params.Offset())
|
|
if err != nil {
|
|
return UserLabelsList{}, err
|
|
}
|
|
defer rows.Close()
|
|
|
|
labels := make([]map[string]any, 0)
|
|
for rows.Next() {
|
|
var id, name, color string
|
|
var createdAt any
|
|
if err := rows.Scan(&id, &name, &color, &createdAt); err != nil {
|
|
return UserLabelsList{}, err
|
|
}
|
|
labels = append(labels, map[string]any{
|
|
"id": id, "name": name, "color": color, "created_at": createdAt,
|
|
})
|
|
}
|
|
if err := rows.Err(); err != nil {
|
|
return UserLabelsList{}, err
|
|
}
|
|
|
|
return UserLabelsList{
|
|
Labels: labels,
|
|
Pagination: params.Meta(&total),
|
|
}, nil
|
|
}
|
|
|
|
func (s *Service) CreateUserLabel(ctx context.Context, externalID string, req *createUserLabelRequest) (string, error) {
|
|
var id string
|
|
err := s.db.QueryRow(ctx, `
|
|
INSERT INTO mail_user_labels (user_id, name, color)
|
|
VALUES ((SELECT id FROM users WHERE external_id = $1), $2, $3)
|
|
RETURNING id
|
|
`, externalID, req.Name, req.Color).Scan(&id)
|
|
if err != nil {
|
|
if isUniqueViolation(err) {
|
|
return "", ErrDuplicateLabel
|
|
}
|
|
return "", err
|
|
}
|
|
return id, nil
|
|
}
|
|
|
|
func (s *Service) UpdateUserLabel(ctx context.Context, externalID, labelID string, req *updateUserLabelRequest) error {
|
|
result, err := s.db.Exec(ctx, `
|
|
UPDATE mail_user_labels SET name = $1, color = $2
|
|
WHERE id = $3 AND user_id = (SELECT id FROM users WHERE external_id = $4)
|
|
`, req.Name, req.Color, labelID, externalID)
|
|
if err != nil {
|
|
if isUniqueViolation(err) {
|
|
return ErrDuplicateLabel
|
|
}
|
|
return err
|
|
}
|
|
if result.RowsAffected() == 0 {
|
|
return ErrNotFound
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (s *Service) DeleteUserLabel(ctx context.Context, externalID, labelID string) error {
|
|
result, err := s.db.Exec(ctx, `
|
|
DELETE FROM mail_user_labels
|
|
WHERE id = $1 AND user_id = (SELECT id FROM users WHERE external_id = $2)
|
|
`, labelID, externalID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if result.RowsAffected() == 0 {
|
|
return ErrNotFound
|
|
}
|
|
if s.audit != nil {
|
|
s.audit.Log(ctx, externalID, securityaudit.ActionCriticalDeletion, map[string]any{
|
|
"target": "mail_user_label", "label_id": labelID,
|
|
})
|
|
}
|
|
return nil
|
|
}
|