Files
mira/backend/internal/calendar/attachments.go
2026-06-09 15:57:45 -03:00

166 lines
4.5 KiB
Go

package calendar
import (
"context"
"errors"
"time"
"github.com/jackc/pgx/v5"
)
var ErrAttachmentNotFound = errors.New("attachment not found")
type Attachment struct {
ID string `json:"id"`
CalendarItemID string `json:"calendar_item_id"`
OriginalFilename string `json:"original_filename"`
StoredFilename string `json:"stored_filename"`
MimeType string `json:"mime_type"`
SizeBytes int64 `json:"size_bytes"`
StorageDriver string `json:"storage_driver"`
StoragePath string `json:"-"`
CreatedBy *string `json:"created_by"`
CreatedAt time.Time `json:"created_at"`
}
type CreateAttachmentInput struct {
CalendarItemID string
OriginalFilename string
StoredFilename string
MimeType string
SizeBytes int64
StorageDriver string
StoragePath string
CreatedBy string
}
func (s Store) CreateAttachment(ctx context.Context, input CreateAttachmentInput) (Attachment, error) {
row := s.db.QueryRow(ctx, `
INSERT INTO calendar_item_attachments (
calendar_item_id,
original_filename,
stored_filename,
mime_type,
size_bytes,
storage_driver,
storage_path,
created_by
)
VALUES ($1::uuid, $2, $3, $4, $5, $6, $7, NULLIF($8, '')::uuid)
RETURNING
id::text,
calendar_item_id::text,
original_filename,
stored_filename,
mime_type,
size_bytes,
storage_driver,
storage_path,
created_by::text,
created_at
`, input.CalendarItemID, input.OriginalFilename, input.StoredFilename, input.MimeType, input.SizeBytes, input.StorageDriver, input.StoragePath, input.CreatedBy)
return scanAttachment(row)
}
func (s Store) ListAttachments(ctx context.Context, calendarItemID string, viewerUserID string) ([]Attachment, error) {
rows, err := s.db.Query(ctx, `
SELECT
calendar_item_attachments.id::text,
calendar_item_attachments.calendar_item_id::text,
calendar_item_attachments.original_filename,
calendar_item_attachments.stored_filename,
calendar_item_attachments.mime_type,
calendar_item_attachments.size_bytes,
calendar_item_attachments.storage_driver,
calendar_item_attachments.storage_path,
calendar_item_attachments.created_by::text,
calendar_item_attachments.created_at
FROM calendar_item_attachments
INNER JOIN calendar_items ON calendar_items.id = calendar_item_attachments.calendar_item_id
WHERE calendar_item_attachments.calendar_item_id = $1::uuid
AND (
$2 = ''
OR EXISTS (
SELECT 1
FROM client_users
WHERE client_users.client_id = calendar_items.client_id
AND client_users.user_id = $2::uuid
)
)
ORDER BY calendar_item_attachments.created_at DESC
`, calendarItemID, viewerUserID)
if err != nil {
return nil, err
}
defer rows.Close()
attachments := []Attachment{}
for rows.Next() {
attachment, err := scanAttachment(rows)
if err != nil {
return nil, err
}
attachments = append(attachments, attachment)
}
return attachments, rows.Err()
}
func (s Store) FindAttachment(ctx context.Context, id string, viewerUserID string) (Attachment, error) {
row := s.db.QueryRow(ctx, `
SELECT
calendar_item_attachments.id::text,
calendar_item_attachments.calendar_item_id::text,
calendar_item_attachments.original_filename,
calendar_item_attachments.stored_filename,
calendar_item_attachments.mime_type,
calendar_item_attachments.size_bytes,
calendar_item_attachments.storage_driver,
calendar_item_attachments.storage_path,
calendar_item_attachments.created_by::text,
calendar_item_attachments.created_at
FROM calendar_item_attachments
INNER JOIN calendar_items ON calendar_items.id = calendar_item_attachments.calendar_item_id
WHERE calendar_item_attachments.id = $1::uuid
AND (
$2 = ''
OR EXISTS (
SELECT 1
FROM client_users
WHERE client_users.client_id = calendar_items.client_id
AND client_users.user_id = $2::uuid
)
)
`, id, viewerUserID)
return scanAttachment(row)
}
type attachmentScanner interface {
Scan(dest ...any) error
}
func scanAttachment(row attachmentScanner) (Attachment, error) {
var attachment Attachment
err := row.Scan(
&attachment.ID,
&attachment.CalendarItemID,
&attachment.OriginalFilename,
&attachment.StoredFilename,
&attachment.MimeType,
&attachment.SizeBytes,
&attachment.StorageDriver,
&attachment.StoragePath,
&attachment.CreatedBy,
&attachment.CreatedAt,
)
if errors.Is(err, pgx.ErrNoRows) {
return Attachment{}, ErrAttachmentNotFound
}
if err != nil {
return Attachment{}, err
}
return attachment, nil
}