timeline.go

  1// SPDX-FileCopyrightText: Amolith <amolith@secluded.site>
  2//
  3// SPDX-License-Identifier: AGPL-3.0-or-later
  4
  5package person
  6
  7import (
  8	"fmt"
  9	"os"
 10	"strings"
 11
 12	"git.secluded.site/go-lunatask"
 13	"git.secluded.site/lune/internal/client"
 14	"git.secluded.site/lune/internal/dateutil"
 15	"git.secluded.site/lune/internal/ui"
 16	"git.secluded.site/lune/internal/validate"
 17	"github.com/spf13/cobra"
 18)
 19
 20// TimelineCmd adds a timeline note to a person. Exported for potential use by shortcuts.
 21var TimelineCmd = &cobra.Command{
 22	Use:   "timeline ID",
 23	Short: "Add a timeline note",
 24	Long: `Add a timeline note to a person's memory timeline.
 25
 26Use "-" as content flag value to read from stdin.`,
 27	Args: cobra.ExactArgs(1),
 28	RunE: runTimeline,
 29}
 30
 31func init() {
 32	TimelineCmd.Flags().StringP("content", "c", "", "Note content (use - for stdin)")
 33	TimelineCmd.Flags().StringP("date", "d", "", "Date of interaction (natural language)")
 34}
 35
 36func runTimeline(cmd *cobra.Command, args []string) error {
 37	personID, err := validate.Reference(args[0])
 38	if err != nil {
 39		return err
 40	}
 41
 42	apiClient, err := client.New()
 43	if err != nil {
 44		return err
 45	}
 46
 47	builder := apiClient.NewTimelineNote(personID)
 48
 49	if err := applyTimelineContent(cmd, builder); err != nil {
 50		return err
 51	}
 52
 53	if err := applyTimelineDate(cmd, builder); err != nil {
 54		return err
 55	}
 56
 57	note, err := builder.Create(cmd.Context())
 58	if err != nil {
 59		return err
 60	}
 61
 62	fmt.Fprintln(cmd.OutOrStdout(), ui.Success.Render("Created timeline note: "+note.ID))
 63
 64	return nil
 65}
 66
 67func applyTimelineContent(cmd *cobra.Command, builder *lunatask.TimelineNoteBuilder) error {
 68	content, _ := cmd.Flags().GetString("content")
 69	if content == "" {
 70		return nil
 71	}
 72
 73	resolved, err := resolveContent(content)
 74	if err != nil {
 75		return err
 76	}
 77
 78	builder.WithContent(resolved)
 79
 80	return nil
 81}
 82
 83func resolveContent(content string) (string, error) {
 84	if content != "-" {
 85		return content, nil
 86	}
 87
 88	data, err := os.ReadFile("/dev/stdin")
 89	if err != nil {
 90		return "", fmt.Errorf("reading stdin: %w", err)
 91	}
 92
 93	return strings.TrimSpace(string(data)), nil
 94}
 95
 96func applyTimelineDate(cmd *cobra.Command, builder *lunatask.TimelineNoteBuilder) error {
 97	dateStr, _ := cmd.Flags().GetString("date")
 98	if dateStr == "" {
 99		return nil
100	}
101
102	date, err := dateutil.Parse(dateStr)
103	if err != nil {
104		return err
105	}
106
107	builder.OnDate(date)
108
109	return nil
110}