1
0

note.go 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451
  1. package cmd
  2. import (
  3. "context"
  4. "encoding/json"
  5. "fmt"
  6. "os"
  7. "gogs.dmsc.dev/arp/arp_cli/client"
  8. "gogs.dmsc.dev/arp/arp_cli/config"
  9. "github.com/AlecAivazis/survey/v2"
  10. "github.com/olekukonko/tablewriter"
  11. "github.com/urfave/cli/v3"
  12. )
  13. // NoteCommand returns the note command
  14. func NoteCommand() *cli.Command {
  15. return &cli.Command{
  16. Name: "note",
  17. Usage: "Manage notes",
  18. Description: `Manage ARP notes. Notes are text entries belonging to users and associated with services.
  19. Use this command to create, list, update, and delete notes.`,
  20. Commands: []*cli.Command{
  21. {
  22. Name: "list",
  23. Aliases: []string{"ls"},
  24. Usage: "List all notes",
  25. Flags: []cli.Flag{
  26. &cli.BoolFlag{
  27. Name: "json",
  28. Aliases: []string{"j"},
  29. Usage: "Output as JSON",
  30. },
  31. },
  32. Action: noteList,
  33. },
  34. {
  35. Name: "get",
  36. Usage: "Get a note by ID",
  37. Flags: []cli.Flag{
  38. &cli.StringFlag{
  39. Name: "id",
  40. Aliases: []string{"i"},
  41. Usage: "Note ID",
  42. Required: true,
  43. },
  44. &cli.BoolFlag{
  45. Name: "json",
  46. Aliases: []string{"j"},
  47. Usage: "Output as JSON",
  48. },
  49. },
  50. Action: noteGet,
  51. },
  52. {
  53. Name: "create",
  54. Usage: "Create a new note",
  55. Action: noteCreate,
  56. Flags: []cli.Flag{
  57. &cli.StringFlag{
  58. Name: "title",
  59. Aliases: []string{"t"},
  60. Usage: "Note title",
  61. },
  62. &cli.StringFlag{
  63. Name: "content",
  64. Aliases: []string{"c"},
  65. Usage: "Note content",
  66. },
  67. &cli.StringFlag{
  68. Name: "user",
  69. Aliases: []string{"u"},
  70. Usage: "User ID",
  71. },
  72. &cli.StringFlag{
  73. Name: "service",
  74. Aliases: []string{"s"},
  75. Usage: "Service ID",
  76. },
  77. },
  78. },
  79. {
  80. Name: "update",
  81. Usage: "Update a note",
  82. Action: noteUpdate,
  83. Flags: []cli.Flag{
  84. &cli.StringFlag{
  85. Name: "id",
  86. Aliases: []string{"i"},
  87. Usage: "Note ID",
  88. Required: true,
  89. },
  90. &cli.StringFlag{
  91. Name: "title",
  92. Aliases: []string{"t"},
  93. Usage: "Note title",
  94. },
  95. &cli.StringFlag{
  96. Name: "content",
  97. Aliases: []string{"c"},
  98. Usage: "Note content",
  99. },
  100. &cli.StringFlag{
  101. Name: "user",
  102. Aliases: []string{"u"},
  103. Usage: "User ID",
  104. },
  105. &cli.StringFlag{
  106. Name: "service",
  107. Aliases: []string{"s"},
  108. Usage: "Service ID",
  109. },
  110. },
  111. },
  112. {
  113. Name: "delete",
  114. Usage: "Delete a note",
  115. Action: noteDelete,
  116. Flags: []cli.Flag{
  117. &cli.StringFlag{
  118. Name: "id",
  119. Aliases: []string{"i"},
  120. Usage: "Note ID",
  121. Required: true,
  122. },
  123. &cli.BoolFlag{
  124. Name: "yes",
  125. Aliases: []string{"y"},
  126. Usage: "Skip confirmation",
  127. },
  128. },
  129. },
  130. },
  131. }
  132. }
  133. type Note struct {
  134. ID string `json:"id"`
  135. Title string `json:"title"`
  136. Content string `json:"content"`
  137. UserID string `json:"userId"`
  138. User *User `json:"user"`
  139. ServiceID string `json:"serviceId"`
  140. Service *Service `json:"service"`
  141. CreatedAt string `json:"createdAt"`
  142. UpdatedAt string `json:"updatedAt"`
  143. }
  144. func noteList(ctx context.Context, cmd *cli.Command) error {
  145. cfg, err := config.Load()
  146. if err != nil {
  147. return err
  148. }
  149. if err := RequireAuth(cfg); err != nil {
  150. return err
  151. }
  152. c := client.New(cfg.ServerURL)
  153. c.SetToken(cfg.Token)
  154. query := "query Notes { notes { id title content userId user { id email } serviceId createdAt updatedAt } }"
  155. resp, err := c.Query(query, nil)
  156. if err != nil {
  157. return err
  158. }
  159. var result struct {
  160. Notes []Note `json:"notes"`
  161. }
  162. if err := json.Unmarshal(resp.Data, &result); err != nil {
  163. return err
  164. }
  165. if cmd.Bool("json") {
  166. enc := json.NewEncoder(os.Stdout)
  167. enc.SetIndent("", " ")
  168. return enc.Encode(result.Notes)
  169. }
  170. if len(result.Notes) == 0 {
  171. fmt.Println("No notes found.")
  172. return nil
  173. }
  174. table := tablewriter.NewWriter(os.Stdout)
  175. table.Header([]string{"ID", "Title", "User", "Service ID", "Created At"})
  176. for _, n := range result.Notes {
  177. userEmail := ""
  178. if n.User != nil {
  179. userEmail = n.User.Email
  180. }
  181. table.Append([]string{n.ID, n.Title, userEmail, n.ServiceID, n.CreatedAt})
  182. }
  183. table.Render()
  184. return nil
  185. }
  186. func noteGet(ctx context.Context, cmd *cli.Command) error {
  187. cfg, err := config.Load()
  188. if err != nil {
  189. return err
  190. }
  191. if err := RequireAuth(cfg); err != nil {
  192. return err
  193. }
  194. c := client.New(cfg.ServerURL)
  195. c.SetToken(cfg.Token)
  196. id := cmd.String("id")
  197. query := "query Note($id: ID!) { note(id: $id) { id title content userId user { id email } serviceId service { id name } createdAt updatedAt } }"
  198. resp, err := c.Query(query, map[string]interface{}{"id": id})
  199. if err != nil {
  200. return err
  201. }
  202. var result struct {
  203. Note *Note `json:"note"`
  204. }
  205. if err := json.Unmarshal(resp.Data, &result); err != nil {
  206. return err
  207. }
  208. if result.Note == nil {
  209. return fmt.Errorf("note not found")
  210. }
  211. if cmd.Bool("json") {
  212. enc := json.NewEncoder(os.Stdout)
  213. enc.SetIndent("", " ")
  214. return enc.Encode(result.Note)
  215. }
  216. n := result.Note
  217. fmt.Printf("ID: %s\n", n.ID)
  218. fmt.Printf("Title: %s\n", n.Title)
  219. fmt.Printf("Content: %s\n", n.Content)
  220. if n.User != nil {
  221. fmt.Printf("User: %s (%s)\n", n.User.Email, n.UserID)
  222. } else {
  223. fmt.Printf("User ID: %s\n", n.UserID)
  224. }
  225. if n.Service != nil {
  226. fmt.Printf("Service: %s (%s)\n", n.Service.Name, n.ServiceID)
  227. } else {
  228. fmt.Printf("Service ID: %s\n", n.ServiceID)
  229. }
  230. fmt.Printf("Created At: %s\n", n.CreatedAt)
  231. fmt.Printf("Updated At: %s\n", n.UpdatedAt)
  232. return nil
  233. }
  234. func noteCreate(ctx context.Context, cmd *cli.Command) error {
  235. cfg, err := config.Load()
  236. if err != nil {
  237. return err
  238. }
  239. if err := RequireAuth(cfg); err != nil {
  240. return err
  241. }
  242. title := cmd.String("title")
  243. content := cmd.String("content")
  244. userID := cmd.String("user")
  245. serviceID := cmd.String("service")
  246. if title == "" {
  247. prompt := &survey.Input{Message: "Title:"}
  248. if err := survey.AskOne(prompt, &title, survey.WithValidator(survey.Required)); err != nil {
  249. return err
  250. }
  251. }
  252. if content == "" {
  253. prompt := &survey.Multiline{Message: "Content:"}
  254. if err := survey.AskOne(prompt, &content, survey.WithValidator(survey.Required)); err != nil {
  255. return err
  256. }
  257. }
  258. if userID == "" {
  259. prompt := &survey.Input{Message: "User ID:"}
  260. if err := survey.AskOne(prompt, &userID, survey.WithValidator(survey.Required)); err != nil {
  261. return err
  262. }
  263. }
  264. if serviceID == "" {
  265. prompt := &survey.Input{Message: "Service ID:"}
  266. if err := survey.AskOne(prompt, &serviceID, survey.WithValidator(survey.Required)); err != nil {
  267. return err
  268. }
  269. }
  270. c := client.New(cfg.ServerURL)
  271. c.SetToken(cfg.Token)
  272. mutation := `mutation CreateNote($input: NewNote!) { createNote(input: $input) { id title content userId user { id email } serviceId createdAt updatedAt } }`
  273. input := map[string]interface{}{
  274. "title": title,
  275. "content": content,
  276. "userId": userID,
  277. "serviceId": serviceID,
  278. }
  279. resp, err := c.Mutation(mutation, map[string]interface{}{"input": input})
  280. if err != nil {
  281. return err
  282. }
  283. var result struct {
  284. CreateNote *Note `json:"createNote"`
  285. }
  286. if err := json.Unmarshal(resp.Data, &result); err != nil {
  287. return err
  288. }
  289. if result.CreateNote == nil {
  290. return fmt.Errorf("failed to create note")
  291. }
  292. fmt.Printf("Note created successfully!\n")
  293. fmt.Printf("ID: %s\n", result.CreateNote.ID)
  294. fmt.Printf("Title: %s\n", result.CreateNote.Title)
  295. return nil
  296. }
  297. func noteUpdate(ctx context.Context, cmd *cli.Command) error {
  298. cfg, err := config.Load()
  299. if err != nil {
  300. return err
  301. }
  302. if err := RequireAuth(cfg); err != nil {
  303. return err
  304. }
  305. id := cmd.String("id")
  306. title := cmd.String("title")
  307. content := cmd.String("content")
  308. userID := cmd.String("user")
  309. serviceID := cmd.String("service")
  310. if title == "" && content == "" && userID == "" && serviceID == "" {
  311. fmt.Println("No updates provided. Use flags to specify what to update.")
  312. return nil
  313. }
  314. c := client.New(cfg.ServerURL)
  315. c.SetToken(cfg.Token)
  316. input := make(map[string]interface{})
  317. if title != "" {
  318. input["title"] = title
  319. }
  320. if content != "" {
  321. input["content"] = content
  322. }
  323. if userID != "" {
  324. input["userId"] = userID
  325. }
  326. if serviceID != "" {
  327. input["serviceId"] = serviceID
  328. }
  329. mutation := `mutation UpdateNote($id: ID!, $input: UpdateNoteInput!) { updateNote(id: $id, input: $input) { id title content userId serviceId createdAt updatedAt } }`
  330. resp, err := c.Mutation(mutation, map[string]interface{}{"id": id, "input": input})
  331. if err != nil {
  332. return err
  333. }
  334. var result struct {
  335. UpdateNote *Note `json:"updateNote"`
  336. }
  337. if err := json.Unmarshal(resp.Data, &result); err != nil {
  338. return err
  339. }
  340. if result.UpdateNote == nil {
  341. return fmt.Errorf("note not found")
  342. }
  343. fmt.Printf("Note updated successfully!\n")
  344. fmt.Printf("ID: %s\n", result.UpdateNote.ID)
  345. fmt.Printf("Title: %s\n", result.UpdateNote.Title)
  346. return nil
  347. }
  348. func noteDelete(ctx context.Context, cmd *cli.Command) error {
  349. cfg, err := config.Load()
  350. if err != nil {
  351. return err
  352. }
  353. if err := RequireAuth(cfg); err != nil {
  354. return err
  355. }
  356. id := cmd.String("id")
  357. skipConfirm := cmd.Bool("yes")
  358. if !skipConfirm {
  359. confirm := false
  360. prompt := &survey.Confirm{
  361. Message: fmt.Sprintf("Are you sure you want to delete note %s?", id),
  362. Default: false,
  363. }
  364. if err := survey.AskOne(prompt, &confirm); err != nil {
  365. return err
  366. }
  367. if !confirm {
  368. fmt.Println("Deletion cancelled.")
  369. return nil
  370. }
  371. }
  372. c := client.New(cfg.ServerURL)
  373. c.SetToken(cfg.Token)
  374. mutation := `mutation DeleteNote($id: ID!) { deleteNote(id: $id) }`
  375. resp, err := c.Mutation(mutation, map[string]interface{}{"id": id})
  376. if err != nil {
  377. return err
  378. }
  379. var result struct {
  380. DeleteNote bool `json:"deleteNote"`
  381. }
  382. if err := json.Unmarshal(resp.Data, &result); err != nil {
  383. return err
  384. }
  385. if result.DeleteNote {
  386. fmt.Printf("Note %s deleted successfully.\n", id)
  387. } else {
  388. fmt.Printf("Failed to delete note %s.\n", id)
  389. }
  390. return nil
  391. }