330 lines
8.5 KiB
Go
330 lines
8.5 KiB
Go
package calendar
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"time"
|
|
|
|
"github.com/jackc/pgx/v5"
|
|
)
|
|
|
|
var ErrCalendarItemNotFound = errors.New("calendar item not found")
|
|
|
|
type CalendarItem struct {
|
|
ID string `json:"id"`
|
|
ClientID string `json:"client_id"`
|
|
ClientName string `json:"client_name"`
|
|
Title string `json:"title"`
|
|
Description string `json:"description"`
|
|
ContentType string `json:"content_type"`
|
|
Status string `json:"status"`
|
|
OwnerID *string `json:"owner_id"`
|
|
ScheduledDate string `json:"scheduled_date"`
|
|
ScheduledAt *time.Time `json:"scheduled_at"`
|
|
CopyText string `json:"copy_text"`
|
|
InternalNotes string `json:"internal_notes"`
|
|
ClientNotes string `json:"client_notes"`
|
|
CreatedBy *string `json:"created_by"`
|
|
CreatedAt time.Time `json:"created_at"`
|
|
UpdatedAt time.Time `json:"updated_at"`
|
|
}
|
|
|
|
type ListCalendarItemsFilter struct {
|
|
ClientID string
|
|
ViewerUserID string
|
|
From string
|
|
To string
|
|
}
|
|
|
|
func (s Store) ListCalendarItems(ctx context.Context, filter ListCalendarItemsFilter) ([]CalendarItem, error) {
|
|
rows, err := s.db.Query(ctx, `
|
|
SELECT
|
|
calendar_items.id::text,
|
|
calendar_items.client_id::text,
|
|
clients.name,
|
|
calendar_items.title,
|
|
calendar_items.description,
|
|
calendar_items.content_type,
|
|
calendar_items.status,
|
|
calendar_items.owner_id::text,
|
|
calendar_items.scheduled_date::text,
|
|
calendar_items.scheduled_at,
|
|
calendar_items.copy_text,
|
|
calendar_items.internal_notes,
|
|
calendar_items.client_notes,
|
|
calendar_items.created_by::text,
|
|
calendar_items.created_at,
|
|
calendar_items.updated_at
|
|
FROM calendar_items
|
|
INNER JOIN clients ON clients.id = calendar_items.client_id
|
|
WHERE calendar_items.scheduled_date >= $1::date
|
|
AND calendar_items.scheduled_date <= $2::date
|
|
AND ($3 = '' OR calendar_items.client_id::text = $3)
|
|
AND (
|
|
$4 = ''
|
|
OR EXISTS (
|
|
SELECT 1
|
|
FROM client_users
|
|
WHERE client_users.client_id = calendar_items.client_id
|
|
AND client_users.user_id = $4::uuid
|
|
)
|
|
)
|
|
ORDER BY calendar_items.scheduled_date ASC, calendar_items.created_at ASC
|
|
`, filter.From, filter.To, filter.ClientID, filter.ViewerUserID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
|
|
items := []CalendarItem{}
|
|
for rows.Next() {
|
|
item, err := scanCalendarItem(rows)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
items = append(items, item)
|
|
}
|
|
|
|
return items, rows.Err()
|
|
}
|
|
|
|
func (s Store) FindCalendarItem(ctx context.Context, id string, viewerUserID string) (CalendarItem, error) {
|
|
row := s.db.QueryRow(ctx, `
|
|
SELECT
|
|
calendar_items.id::text,
|
|
calendar_items.client_id::text,
|
|
clients.name,
|
|
calendar_items.title,
|
|
calendar_items.description,
|
|
calendar_items.content_type,
|
|
calendar_items.status,
|
|
calendar_items.owner_id::text,
|
|
calendar_items.scheduled_date::text,
|
|
calendar_items.scheduled_at,
|
|
calendar_items.copy_text,
|
|
calendar_items.internal_notes,
|
|
calendar_items.client_notes,
|
|
calendar_items.created_by::text,
|
|
calendar_items.created_at,
|
|
calendar_items.updated_at
|
|
FROM calendar_items
|
|
INNER JOIN clients ON clients.id = calendar_items.client_id
|
|
WHERE calendar_items.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 scanCalendarItem(row)
|
|
}
|
|
|
|
type CreateCalendarItemInput struct {
|
|
ClientID string
|
|
Title string
|
|
Description string
|
|
ContentType string
|
|
Status string
|
|
ScheduledDate string
|
|
CopyText string
|
|
InternalNotes string
|
|
ClientNotes string
|
|
CreatedBy string
|
|
}
|
|
|
|
func (s Store) CreateCalendarItem(ctx context.Context, input CreateCalendarItemInput) (CalendarItem, error) {
|
|
row := s.db.QueryRow(ctx, `
|
|
INSERT INTO calendar_items (
|
|
client_id,
|
|
title,
|
|
description,
|
|
content_type,
|
|
status,
|
|
scheduled_date,
|
|
copy_text,
|
|
internal_notes,
|
|
client_notes,
|
|
created_by
|
|
)
|
|
VALUES ($1::uuid, $2, $3, $4, $5, $6::date, $7, $8, $9, NULLIF($10, '')::uuid)
|
|
RETURNING
|
|
calendar_items.id::text,
|
|
calendar_items.client_id::text,
|
|
(SELECT name FROM clients WHERE clients.id = calendar_items.client_id),
|
|
calendar_items.title,
|
|
calendar_items.description,
|
|
calendar_items.content_type,
|
|
calendar_items.status,
|
|
calendar_items.owner_id::text,
|
|
calendar_items.scheduled_date::text,
|
|
calendar_items.scheduled_at,
|
|
calendar_items.copy_text,
|
|
calendar_items.internal_notes,
|
|
calendar_items.client_notes,
|
|
calendar_items.created_by::text,
|
|
calendar_items.created_at,
|
|
calendar_items.updated_at
|
|
`,
|
|
input.ClientID,
|
|
input.Title,
|
|
input.Description,
|
|
input.ContentType,
|
|
input.Status,
|
|
input.ScheduledDate,
|
|
input.CopyText,
|
|
input.InternalNotes,
|
|
input.ClientNotes,
|
|
input.CreatedBy,
|
|
)
|
|
|
|
return scanCalendarItem(row)
|
|
}
|
|
|
|
type UpdateCalendarItemInput struct {
|
|
ID string
|
|
Title string
|
|
UpdateTitle bool
|
|
Description string
|
|
UpdateDescription bool
|
|
Status string
|
|
UpdateStatus bool
|
|
ScheduledDate string
|
|
UpdateScheduledDate bool
|
|
CopyText string
|
|
UpdateCopyText bool
|
|
InternalNotes string
|
|
UpdateInternalNotes bool
|
|
ClientNotes string
|
|
UpdateClientNotes bool
|
|
}
|
|
|
|
func (s Store) UpdateCalendarItem(ctx context.Context, input UpdateCalendarItemInput) (CalendarItem, error) {
|
|
row := s.db.QueryRow(ctx, `
|
|
UPDATE calendar_items
|
|
SET
|
|
title = CASE WHEN $2 THEN $3 ELSE title END,
|
|
description = CASE WHEN $4 THEN $5 ELSE description END,
|
|
status = CASE WHEN $6 THEN $7 ELSE status END,
|
|
scheduled_date = CASE WHEN $8 THEN NULLIF($9, '')::date ELSE scheduled_date END,
|
|
copy_text = CASE WHEN $10 THEN $11 ELSE copy_text END,
|
|
internal_notes = CASE WHEN $12 THEN $13 ELSE internal_notes END,
|
|
client_notes = CASE WHEN $14 THEN $15 ELSE client_notes END,
|
|
updated_at = now()
|
|
WHERE id = $1::uuid
|
|
RETURNING
|
|
calendar_items.id::text,
|
|
calendar_items.client_id::text,
|
|
(SELECT name FROM clients WHERE clients.id = calendar_items.client_id),
|
|
calendar_items.title,
|
|
calendar_items.description,
|
|
calendar_items.content_type,
|
|
calendar_items.status,
|
|
calendar_items.owner_id::text,
|
|
calendar_items.scheduled_date::text,
|
|
calendar_items.scheduled_at,
|
|
calendar_items.copy_text,
|
|
calendar_items.internal_notes,
|
|
calendar_items.client_notes,
|
|
calendar_items.created_by::text,
|
|
calendar_items.created_at,
|
|
calendar_items.updated_at
|
|
`,
|
|
input.ID,
|
|
input.UpdateTitle,
|
|
input.Title,
|
|
input.UpdateDescription,
|
|
input.Description,
|
|
input.UpdateStatus,
|
|
input.Status,
|
|
input.UpdateScheduledDate,
|
|
input.ScheduledDate,
|
|
input.UpdateCopyText,
|
|
input.CopyText,
|
|
input.UpdateInternalNotes,
|
|
input.InternalNotes,
|
|
input.UpdateClientNotes,
|
|
input.ClientNotes,
|
|
)
|
|
|
|
return scanCalendarItem(row)
|
|
}
|
|
|
|
func (s Store) CancelCalendarItem(ctx context.Context, id string) (CalendarItem, error) {
|
|
row := s.db.QueryRow(ctx, `
|
|
UPDATE calendar_items
|
|
SET status = 'cancelado', updated_at = now()
|
|
WHERE id = $1::uuid
|
|
RETURNING
|
|
calendar_items.id::text,
|
|
calendar_items.client_id::text,
|
|
(SELECT name FROM clients WHERE clients.id = calendar_items.client_id),
|
|
calendar_items.title,
|
|
calendar_items.description,
|
|
calendar_items.content_type,
|
|
calendar_items.status,
|
|
calendar_items.owner_id::text,
|
|
calendar_items.scheduled_date::text,
|
|
calendar_items.scheduled_at,
|
|
calendar_items.copy_text,
|
|
calendar_items.internal_notes,
|
|
calendar_items.client_notes,
|
|
calendar_items.created_by::text,
|
|
calendar_items.created_at,
|
|
calendar_items.updated_at
|
|
`, id)
|
|
|
|
return scanCalendarItem(row)
|
|
}
|
|
|
|
func (s Store) DeleteCalendarItem(ctx context.Context, id string) error {
|
|
command, err := s.db.Exec(ctx, `
|
|
DELETE FROM calendar_items
|
|
WHERE id = $1::uuid
|
|
`, id)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if command.RowsAffected() == 0 {
|
|
return ErrCalendarItemNotFound
|
|
}
|
|
return nil
|
|
}
|
|
|
|
type calendarItemScanner interface {
|
|
Scan(dest ...any) error
|
|
}
|
|
|
|
func scanCalendarItem(row calendarItemScanner) (CalendarItem, error) {
|
|
var item CalendarItem
|
|
err := row.Scan(
|
|
&item.ID,
|
|
&item.ClientID,
|
|
&item.ClientName,
|
|
&item.Title,
|
|
&item.Description,
|
|
&item.ContentType,
|
|
&item.Status,
|
|
&item.OwnerID,
|
|
&item.ScheduledDate,
|
|
&item.ScheduledAt,
|
|
&item.CopyText,
|
|
&item.InternalNotes,
|
|
&item.ClientNotes,
|
|
&item.CreatedBy,
|
|
&item.CreatedAt,
|
|
&item.UpdatedAt,
|
|
)
|
|
if errors.Is(err, pgx.ErrNoRows) {
|
|
return CalendarItem{}, ErrCalendarItemNotFound
|
|
}
|
|
if err != nil {
|
|
return CalendarItem{}, err
|
|
}
|
|
return item, nil
|
|
}
|