a.go

  1// SPDX-FileCopyrightText: Amolith <amolith@secluded.site>
  2//
  3// SPDX-License-Identifier: AGPL-3.0-or-later
  4
  5package t
  6
  7import (
  8	"errors"
  9	"fmt"
 10	"strings"
 11
 12	"git.secluded.site/np/cmd/shared"
 13	"git.secluded.site/np/internal/db"
 14	"git.secluded.site/np/internal/event"
 15	"git.secluded.site/np/internal/task"
 16	"github.com/spf13/cobra"
 17)
 18
 19var aCmd = &cobra.Command{
 20	Use:   "a",
 21	Short: "Add tasks",
 22	Long:  `Add one or more tasks to the session`,
 23	RunE:  runAddTasks,
 24}
 25
 26func init() {
 27	TCmd.AddCommand(aCmd)
 28
 29	aCmd.Flags().StringArrayP("title", "t", []string{}, "Task title (required, repeatable)")
 30	aCmd.Flags().StringArrayP("description", "d", []string{}, "Task description (required, repeatable)")
 31	_ = aCmd.MarkFlagRequired("title")
 32	_ = aCmd.MarkFlagRequired("description")
 33}
 34
 35func runAddTasks(cmd *cobra.Command, _ []string) error {
 36	env, err := shared.Environment(cmd)
 37	if err != nil {
 38		return err
 39	}
 40
 41	sessionDoc, found, err := shared.ActiveSession(cmd, env)
 42	if err != nil {
 43		return err
 44	}
 45	if !found {
 46		return nil
 47	}
 48
 49	titles, err := cmd.Flags().GetStringArray("title")
 50	if err != nil {
 51		return err
 52	}
 53	descriptions, err := cmd.Flags().GetStringArray("description")
 54	if err != nil {
 55		return err
 56	}
 57
 58	if len(titles) != len(descriptions) {
 59		_, _ = fmt.Fprintln(cmd.OutOrStdout(), env.Localizer.T("task.add.count_mismatch"))
 60		return nil
 61	}
 62	if len(titles) == 0 {
 63		_, _ = fmt.Fprintln(cmd.OutOrStdout(), env.Localizer.T("task.add.none_provided"))
 64		return nil
 65	}
 66
 67	type taskInput struct {
 68		title       string
 69		description string
 70		id          string
 71	}
 72
 73	var inputs []taskInput
 74	for i := range titles {
 75		title := strings.TrimSpace(titles[i])
 76		description := strings.TrimSpace(descriptions[i])
 77
 78		if title == "" {
 79			_, _ = fmt.Fprintf(cmd.OutOrStdout(), env.Localizer.T("task.add.title_empty_at"), i+1)
 80			return nil
 81		}
 82
 83		id := task.GenerateID(sessionDoc.SID, title, description)
 84		inputs = append(inputs, taskInput{
 85			title:       title,
 86			description: description,
 87			id:          id,
 88		})
 89	}
 90
 91	var lastUpdated task.Task
 92	var addedCount int
 93
 94	err = env.DB.Update(cmd.Context(), func(txn *db.Txn) error {
 95		taskTxn := env.TaskStore.WithTxn(txn)
 96		eventTxn := env.EventStore.WithTxn(txn)
 97		sessionTxn := env.SessionStore.WithTxn(txn)
 98
 99		for _, input := range inputs {
100			exists, err := taskTxn.Exists(sessionDoc.SID, input.id)
101			if err != nil {
102				return err
103			}
104			if exists {
105				continue
106			}
107
108			seq, err := eventTxn.LatestSequence(sessionDoc.SID)
109			if err != nil {
110				return err
111			}
112			nextSeq := seq + 1
113
114			created, err := taskTxn.Create(sessionDoc.SID, task.CreateParams{
115				ID:          input.id,
116				Title:       input.title,
117				Description: input.description,
118				Status:      task.StatusPending,
119				CreatedSeq:  nextSeq,
120			})
121			if err != nil {
122				return err
123			}
124
125			_, err = eventTxn.Append(sessionDoc.SID, event.BuildTaskAdded(shared.CommandString(), "", created))
126			if err != nil {
127				return err
128			}
129
130			lastUpdated = created
131			addedCount++
132		}
133
134		if addedCount > 0 {
135			_, err := sessionTxn.TouchAt(sessionDoc.SID, lastUpdated.UpdatedAt)
136			if err != nil {
137				return err
138			}
139		}
140
141		return nil
142	})
143	if err != nil {
144		if errors.Is(err, task.ErrEmptyTitle) {
145			_, _ = fmt.Fprintln(cmd.OutOrStdout(), env.Localizer.T("task.add.title_empty"))
146			return nil
147		}
148		return err
149	}
150
151	if addedCount == 0 {
152		return nil
153	}
154
155	if addedCount == 1 {
156		_, _ = fmt.Fprintln(cmd.OutOrStdout(), "Added")
157		return nil
158	}
159
160	// Multiple tasks added, show full plan
161	if _, err := shared.PrintPlan(cmd, env, sessionDoc.SID); err != nil {
162		return err
163	}
164
165	out := cmd.OutOrStdout()
166	_, _ = fmt.Fprintln(out, "")
167	_, _ = fmt.Fprintf(out, env.Localizer.T("task.add.success"), addedCount)
168	_, _ = fmt.Fprintln(out, env.Localizer.T("task.add.guidance"))
169
170	return nil
171}