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 := ui.Spin("Creating timeline note…", func() (*lunatask.PersonTimelineNote, error) {
 58		return builder.Create(cmd.Context())
 59	})
 60	if err != nil {
 61		return err
 62	}
 63
 64	fmt.Fprintln(cmd.OutOrStdout(), ui.Success.Render("Created timeline note: "+note.ID))
 65
 66	return nil
 67}
 68
 69func applyTimelineContent(cmd *cobra.Command, builder *lunatask.TimelineNoteBuilder) error {
 70	content, _ := cmd.Flags().GetString("content")
 71	if content == "" {
 72		return nil
 73	}
 74
 75	resolved, err := resolveContent(content)
 76	if err != nil {
 77		return err
 78	}
 79
 80	builder.WithContent(resolved)
 81
 82	return nil
 83}
 84
 85func resolveContent(content string) (string, error) {
 86	if content != "-" {
 87		return content, nil
 88	}
 89
 90	data, err := os.ReadFile("/dev/stdin")
 91	if err != nil {
 92		return "", fmt.Errorf("reading stdin: %w", err)
 93	}
 94
 95	return strings.TrimSpace(string(data)), nil
 96}
 97
 98func applyTimelineDate(cmd *cobra.Command, builder *lunatask.TimelineNoteBuilder) error {
 99	dateStr, _ := cmd.Flags().GetString("date")
100	if dateStr == "" {
101		return nil
102	}
103
104	date, err := dateutil.Parse(dateStr)
105	if err != nil {
106		return err
107	}
108
109	builder.OnDate(date)
110
111	return nil
112}