162 lines
4.3 KiB
Go
162 lines
4.3 KiB
Go
package mail
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
|
|
"github.com/jackc/pgx/v5"
|
|
|
|
"github.com/ultisuite/ulti-backend/internal/api/query"
|
|
"github.com/ultisuite/ulti-backend/internal/securityaudit"
|
|
)
|
|
|
|
type SignaturesList struct {
|
|
Signatures []map[string]any `json:"signatures"`
|
|
Pagination query.PaginationMeta `json:"pagination,omitempty"`
|
|
}
|
|
|
|
func scanSignature(id, name, html string, sortOrder int, createdAt, updatedAt any) map[string]any {
|
|
return map[string]any{
|
|
"id": id,
|
|
"name": name,
|
|
"html": html,
|
|
"sort_order": sortOrder,
|
|
"created_at": createdAt,
|
|
"updated_at": updatedAt,
|
|
}
|
|
}
|
|
|
|
func (s *Service) verifySignatureOwnership(ctx context.Context, externalID, signatureID string) error {
|
|
var exists bool
|
|
err := s.db.QueryRow(ctx, `
|
|
SELECT EXISTS(
|
|
SELECT 1 FROM mail_signatures ms
|
|
JOIN users u ON ms.user_id = u.id
|
|
WHERE ms.id = $1 AND u.external_id = $2
|
|
)
|
|
`, signatureID, externalID).Scan(&exists)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if !exists {
|
|
return ErrNotFound
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (s *Service) ListSignatures(ctx context.Context, externalID string, params query.ListParams) (SignaturesList, error) {
|
|
var total int64
|
|
if err := s.db.QueryRow(ctx, `
|
|
SELECT COUNT(*) FROM mail_signatures ms
|
|
JOIN users u ON ms.user_id = u.id
|
|
WHERE u.external_id = $1
|
|
`, externalID).Scan(&total); err != nil {
|
|
return SignaturesList{}, err
|
|
}
|
|
|
|
rows, err := s.db.Query(ctx, `
|
|
SELECT ms.id, ms.name, ms.html, ms.sort_order, ms.created_at, ms.updated_at
|
|
FROM mail_signatures ms
|
|
JOIN users u ON ms.user_id = u.id
|
|
WHERE u.external_id = $1
|
|
ORDER BY ms.sort_order ASC, ms.created_at ASC
|
|
LIMIT $2 OFFSET $3
|
|
`, externalID, params.Limit(), params.Offset())
|
|
if err != nil {
|
|
return SignaturesList{}, err
|
|
}
|
|
defer rows.Close()
|
|
|
|
signatures := make([]map[string]any, 0)
|
|
for rows.Next() {
|
|
var id, name, html string
|
|
var sortOrder int
|
|
var createdAt, updatedAt any
|
|
if err := rows.Scan(&id, &name, &html, &sortOrder, &createdAt, &updatedAt); err != nil {
|
|
return SignaturesList{}, err
|
|
}
|
|
signatures = append(signatures, scanSignature(id, name, html, sortOrder, createdAt, updatedAt))
|
|
}
|
|
if err := rows.Err(); err != nil {
|
|
return SignaturesList{}, err
|
|
}
|
|
|
|
return SignaturesList{
|
|
Signatures: signatures,
|
|
Pagination: params.Meta(&total),
|
|
}, nil
|
|
}
|
|
|
|
func (s *Service) GetSignature(ctx context.Context, externalID, signatureID string) (map[string]any, error) {
|
|
var id, name, html string
|
|
var sortOrder int
|
|
var createdAt, updatedAt any
|
|
err := s.db.QueryRow(ctx, `
|
|
SELECT ms.id, ms.name, ms.html, ms.sort_order, ms.created_at, ms.updated_at
|
|
FROM mail_signatures ms
|
|
JOIN users u ON ms.user_id = u.id
|
|
WHERE ms.id = $1 AND u.external_id = $2
|
|
`, signatureID, externalID).Scan(&id, &name, &html, &sortOrder, &createdAt, &updatedAt)
|
|
if err != nil {
|
|
if errors.Is(err, pgx.ErrNoRows) {
|
|
return nil, ErrNotFound
|
|
}
|
|
return nil, err
|
|
}
|
|
return scanSignature(id, name, html, sortOrder, createdAt, updatedAt), nil
|
|
}
|
|
|
|
func (s *Service) CreateSignature(ctx context.Context, externalID string, req *createSignatureRequest) (string, error) {
|
|
userID, err := s.ResolveUserID(ctx, externalID)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
var id string
|
|
err = s.db.QueryRow(ctx, `
|
|
INSERT INTO mail_signatures (user_id, name, html)
|
|
VALUES ($1, $2, $3)
|
|
RETURNING id
|
|
`, userID, req.Name, req.HTML).Scan(&id)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
return id, nil
|
|
}
|
|
|
|
func (s *Service) UpdateSignature(ctx context.Context, externalID, signatureID string, req *updateSignatureRequest) error {
|
|
result, err := s.db.Exec(ctx, `
|
|
UPDATE mail_signatures ms SET
|
|
name = $1, html = $2, updated_at = NOW()
|
|
FROM users u
|
|
WHERE ms.id = $3 AND ms.user_id = u.id AND u.external_id = $4
|
|
`, req.Name, req.HTML, signatureID, externalID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if result.RowsAffected() == 0 {
|
|
return ErrNotFound
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (s *Service) DeleteSignature(ctx context.Context, externalID, signatureID string) error {
|
|
result, err := s.db.Exec(ctx, `
|
|
DELETE FROM mail_signatures ms
|
|
USING users u
|
|
WHERE ms.id = $1 AND ms.user_id = u.id AND u.external_id = $2
|
|
`, signatureID, 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_signature", "signature_id": signatureID,
|
|
})
|
|
}
|
|
return nil
|
|
}
|