package cmd import ( "context" "encoding/json" "fmt" "os" "gogs.dmsc.dev/arp/arp_cli/client" "gogs.dmsc.dev/arp/arp_cli/config" "github.com/AlecAivazis/survey/v2" "github.com/olekukonko/tablewriter" "github.com/urfave/cli/v3" ) // NoteCommand returns the note command func NoteCommand() *cli.Command { return &cli.Command{ Name: "note", Usage: "Manage notes", Description: `Manage ARP notes. Notes are text entries belonging to users and associated with services. Use this command to create, list, update, and delete notes.`, Commands: []*cli.Command{ { Name: "list", Aliases: []string{"ls"}, Usage: "List all notes", Flags: []cli.Flag{ &cli.BoolFlag{ Name: "json", Aliases: []string{"j"}, Usage: "Output as JSON", }, }, Action: noteList, }, { Name: "get", Usage: "Get a note by ID", Flags: []cli.Flag{ &cli.StringFlag{ Name: "id", Aliases: []string{"i"}, Usage: "Note ID", Required: true, }, &cli.BoolFlag{ Name: "json", Aliases: []string{"j"}, Usage: "Output as JSON", }, }, Action: noteGet, }, { Name: "create", Usage: "Create a new note", Action: noteCreate, Flags: []cli.Flag{ &cli.StringFlag{ Name: "title", Aliases: []string{"t"}, Usage: "Note title", }, &cli.StringFlag{ Name: "content", Aliases: []string{"c"}, Usage: "Note content", }, &cli.StringFlag{ Name: "user", Aliases: []string{"u"}, Usage: "User ID", }, &cli.StringFlag{ Name: "service", Aliases: []string{"s"}, Usage: "Service ID", }, }, }, { Name: "update", Usage: "Update a note", Action: noteUpdate, Flags: []cli.Flag{ &cli.StringFlag{ Name: "id", Aliases: []string{"i"}, Usage: "Note ID", Required: true, }, &cli.StringFlag{ Name: "title", Aliases: []string{"t"}, Usage: "Note title", }, &cli.StringFlag{ Name: "content", Aliases: []string{"c"}, Usage: "Note content", }, &cli.StringFlag{ Name: "user", Aliases: []string{"u"}, Usage: "User ID", }, &cli.StringFlag{ Name: "service", Aliases: []string{"s"}, Usage: "Service ID", }, }, }, { Name: "delete", Usage: "Delete a note", Action: noteDelete, Flags: []cli.Flag{ &cli.StringFlag{ Name: "id", Aliases: []string{"i"}, Usage: "Note ID", Required: true, }, &cli.BoolFlag{ Name: "yes", Aliases: []string{"y"}, Usage: "Skip confirmation", }, }, }, }, } } type Note struct { ID string `json:"id"` Title string `json:"title"` Content string `json:"content"` UserID string `json:"userId"` User *User `json:"user"` ServiceID string `json:"serviceId"` Service *Service `json:"service"` CreatedAt string `json:"createdAt"` UpdatedAt string `json:"updatedAt"` } func noteList(ctx context.Context, cmd *cli.Command) error { cfg, err := config.Load() if err != nil { return err } if err := RequireAuth(cfg); err != nil { return err } c := client.New(cfg.ServerURL) c.SetToken(cfg.Token) query := "query Notes { notes { id title content userId user { id email } serviceId createdAt updatedAt } }" resp, err := c.Query(query, nil) if err != nil { return err } var result struct { Notes []Note `json:"notes"` } if err := json.Unmarshal(resp.Data, &result); err != nil { return err } if cmd.Bool("json") { enc := json.NewEncoder(os.Stdout) enc.SetIndent("", " ") return enc.Encode(result.Notes) } if len(result.Notes) == 0 { fmt.Println("No notes found.") return nil } table := tablewriter.NewWriter(os.Stdout) table.Header([]string{"ID", "Title", "User", "Service ID", "Created At"}) for _, n := range result.Notes { userEmail := "" if n.User != nil { userEmail = n.User.Email } table.Append([]string{n.ID, n.Title, userEmail, n.ServiceID, n.CreatedAt}) } table.Render() return nil } func noteGet(ctx context.Context, cmd *cli.Command) error { cfg, err := config.Load() if err != nil { return err } if err := RequireAuth(cfg); err != nil { return err } c := client.New(cfg.ServerURL) c.SetToken(cfg.Token) id := cmd.String("id") query := "query Note($id: ID!) { note(id: $id) { id title content userId user { id email } serviceId service { id name } createdAt updatedAt } }" resp, err := c.Query(query, map[string]interface{}{"id": id}) if err != nil { return err } var result struct { Note *Note `json:"note"` } if err := json.Unmarshal(resp.Data, &result); err != nil { return err } if result.Note == nil { return fmt.Errorf("note not found") } if cmd.Bool("json") { enc := json.NewEncoder(os.Stdout) enc.SetIndent("", " ") return enc.Encode(result.Note) } n := result.Note fmt.Printf("ID: %s\n", n.ID) fmt.Printf("Title: %s\n", n.Title) fmt.Printf("Content: %s\n", n.Content) if n.User != nil { fmt.Printf("User: %s (%s)\n", n.User.Email, n.UserID) } else { fmt.Printf("User ID: %s\n", n.UserID) } if n.Service != nil { fmt.Printf("Service: %s (%s)\n", n.Service.Name, n.ServiceID) } else { fmt.Printf("Service ID: %s\n", n.ServiceID) } fmt.Printf("Created At: %s\n", n.CreatedAt) fmt.Printf("Updated At: %s\n", n.UpdatedAt) return nil } func noteCreate(ctx context.Context, cmd *cli.Command) error { cfg, err := config.Load() if err != nil { return err } if err := RequireAuth(cfg); err != nil { return err } title := cmd.String("title") content := cmd.String("content") userID := cmd.String("user") serviceID := cmd.String("service") if title == "" { prompt := &survey.Input{Message: "Title:"} if err := survey.AskOne(prompt, &title, survey.WithValidator(survey.Required)); err != nil { return err } } if content == "" { prompt := &survey.Multiline{Message: "Content:"} if err := survey.AskOne(prompt, &content, survey.WithValidator(survey.Required)); err != nil { return err } } if userID == "" { prompt := &survey.Input{Message: "User ID:"} if err := survey.AskOne(prompt, &userID, survey.WithValidator(survey.Required)); err != nil { return err } } if serviceID == "" { prompt := &survey.Input{Message: "Service ID:"} if err := survey.AskOne(prompt, &serviceID, survey.WithValidator(survey.Required)); err != nil { return err } } c := client.New(cfg.ServerURL) c.SetToken(cfg.Token) mutation := `mutation CreateNote($input: NewNote!) { createNote(input: $input) { id title content userId user { id email } serviceId createdAt updatedAt } }` input := map[string]interface{}{ "title": title, "content": content, "userId": userID, "serviceId": serviceID, } resp, err := c.Mutation(mutation, map[string]interface{}{"input": input}) if err != nil { return err } var result struct { CreateNote *Note `json:"createNote"` } if err := json.Unmarshal(resp.Data, &result); err != nil { return err } if result.CreateNote == nil { return fmt.Errorf("failed to create note") } fmt.Printf("Note created successfully!\n") fmt.Printf("ID: %s\n", result.CreateNote.ID) fmt.Printf("Title: %s\n", result.CreateNote.Title) return nil } func noteUpdate(ctx context.Context, cmd *cli.Command) error { cfg, err := config.Load() if err != nil { return err } if err := RequireAuth(cfg); err != nil { return err } id := cmd.String("id") title := cmd.String("title") content := cmd.String("content") userID := cmd.String("user") serviceID := cmd.String("service") if title == "" && content == "" && userID == "" && serviceID == "" { fmt.Println("No updates provided. Use flags to specify what to update.") return nil } c := client.New(cfg.ServerURL) c.SetToken(cfg.Token) input := make(map[string]interface{}) if title != "" { input["title"] = title } if content != "" { input["content"] = content } if userID != "" { input["userId"] = userID } if serviceID != "" { input["serviceId"] = serviceID } mutation := `mutation UpdateNote($id: ID!, $input: UpdateNoteInput!) { updateNote(id: $id, input: $input) { id title content userId serviceId createdAt updatedAt } }` resp, err := c.Mutation(mutation, map[string]interface{}{"id": id, "input": input}) if err != nil { return err } var result struct { UpdateNote *Note `json:"updateNote"` } if err := json.Unmarshal(resp.Data, &result); err != nil { return err } if result.UpdateNote == nil { return fmt.Errorf("note not found") } fmt.Printf("Note updated successfully!\n") fmt.Printf("ID: %s\n", result.UpdateNote.ID) fmt.Printf("Title: %s\n", result.UpdateNote.Title) return nil } func noteDelete(ctx context.Context, cmd *cli.Command) error { cfg, err := config.Load() if err != nil { return err } if err := RequireAuth(cfg); err != nil { return err } id := cmd.String("id") skipConfirm := cmd.Bool("yes") if !skipConfirm { confirm := false prompt := &survey.Confirm{ Message: fmt.Sprintf("Are you sure you want to delete note %s?", id), Default: false, } if err := survey.AskOne(prompt, &confirm); err != nil { return err } if !confirm { fmt.Println("Deletion cancelled.") return nil } } c := client.New(cfg.ServerURL) c.SetToken(cfg.Token) mutation := `mutation DeleteNote($id: ID!) { deleteNote(id: $id) }` resp, err := c.Mutation(mutation, map[string]interface{}{"id": id}) if err != nil { return err } var result struct { DeleteNote bool `json:"deleteNote"` } if err := json.Unmarshal(resp.Data, &result); err != nil { return err } if result.DeleteNote { fmt.Printf("Note %s deleted successfully.\n", id) } else { fmt.Printf("Failed to delete note %s.\n", id) } return nil }