u.go

  1// SPDX-FileCopyrightText: Amolith <amolith@secluded.site>
  2//
  3// SPDX-License-Identifier: AGPL-3.0-or-later
  4
  5package g
  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/goal"
 16	"github.com/spf13/cobra"
 17)
 18
 19var uCmd = &cobra.Command{
 20	Use:   "u",
 21	Short: "Update goal",
 22	Long:  `Update the goal title or description (requires a reason)`,
 23	RunE:  runUpdateGoal,
 24}
 25
 26func init() {
 27	GCmd.AddCommand(uCmd)
 28
 29	uCmd.Flags().StringP("title", "t", "", "New goal title")
 30	uCmd.Flags().StringP("description", "d", "", "New goal description")
 31	uCmd.Flags().StringP("reason", "r", "", "Reason for updating the goal (required)")
 32	_ = uCmd.MarkFlagRequired("reason")
 33}
 34
 35func runUpdateGoal(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	current, err := env.GoalStore.Get(cmd.Context(), sessionDoc.SID)
 50	if err != nil {
 51		if errors.Is(err, goal.ErrNotFound) {
 52			_, _ = fmt.Fprintln(cmd.OutOrStdout(), env.Localizer.T("goal.update.not_set"))
 53			return nil
 54		}
 55		return err
 56	}
 57
 58	titleInput, err := cmd.Flags().GetString("title")
 59	if err != nil {
 60		return err
 61	}
 62	descInput, err := cmd.Flags().GetString("description")
 63	if err != nil {
 64		return err
 65	}
 66	reason, err := cmd.Flags().GetString("reason")
 67	if err != nil {
 68		return err
 69	}
 70
 71	reason = strings.TrimSpace(reason)
 72	if reason == "" {
 73		_, _ = fmt.Fprintln(cmd.OutOrStdout(), env.Localizer.T("goal.update.reason_required"))
 74		return nil
 75	}
 76
 77	newTitle := current.Title
 78	if cmd.Flags().Changed("title") {
 79		newTitle = strings.TrimSpace(titleInput)
 80		if newTitle == "" {
 81			_, _ = fmt.Fprintln(cmd.OutOrStdout(), env.Localizer.T("goal.update.title_empty"))
 82			return nil
 83		}
 84	}
 85
 86	newDescription := current.Description
 87	if cmd.Flags().Changed("description") {
 88		newDescription = strings.TrimSpace(descInput)
 89	}
 90
 91	if !cmd.Flags().Changed("title") && !cmd.Flags().Changed("description") {
 92		_, _ = fmt.Fprintln(cmd.OutOrStdout(), env.Localizer.T("goal.update.no_changes_provided"))
 93		return nil
 94	}
 95
 96	if newTitle == current.Title && newDescription == current.Description {
 97		_, _ = fmt.Fprintln(cmd.OutOrStdout(), env.Localizer.T("goal.update.no_changes_made"))
 98		return nil
 99	}
100
101	var updated goal.Document
102	err = env.DB.Update(cmd.Context(), func(txn *db.Txn) error {
103		goalTxn := env.GoalStore.WithTxn(txn)
104
105		var err error
106		updated, err = goalTxn.Set(sessionDoc.SID, newTitle, newDescription)
107		if err != nil {
108			return err
109		}
110
111		sessionTxn := env.SessionStore.WithTxn(txn)
112		if _, err := sessionTxn.TouchAt(sessionDoc.SID, updated.UpdatedAt); err != nil {
113			return err
114		}
115
116		eventTxn := env.EventStore.WithTxn(txn)
117		_, err = eventTxn.Append(sessionDoc.SID, event.BuildGoalUpdated(shared.CommandString(), reason, current, updated))
118		return err
119	})
120	if err != nil {
121		return err
122	}
123
124	if _, err := shared.PrintPlan(cmd, env, sessionDoc.SID); err != nil {
125		return err
126	}
127
128	out := cmd.OutOrStdout()
129	_, _ = fmt.Fprintln(out, "")
130	_, _ = fmt.Fprintln(out, env.Localizer.T("goal.update.guidance"))
131
132	return nil
133}