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}