Files
pop/cmd/attachments.go
Michael Freno 7bbba9f15c FRE-683: Add contacts & attachments management
- Implemented contact CRUD operations (list, add, edit, delete)
- Implemented attachment management (list, upload, download)
- Created internal/contact/manager.go for contact persistence
- Created internal/attachment/manager.go for attachment storage
- Added CLI commands in cmd/contacts.go and cmd/attachments.go
- Integrated contact and attachment commands into root CLI

Files:
- internal/contact/types.go - Contact data models
- internal/contact/manager.go - Contact CRUD operations
- internal/attachment/manager.go - Attachment file operations
- cmd/contacts.go - Contact CLI commands
- cmd/attachments.go - Attachment CLI commands

Contacts stored in ~/.config/pop/contacts.json
Attachments stored in ~/.config/pop/attachments/
2026-04-26 10:26:29 -04:00

125 lines
2.7 KiB
Go

package cmd
import (
"fmt"
"io"
"os"
"github.com/frenocorp/pop/internal/attachment"
"github.com/spf13/cobra"
)
func attachmentCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "attachment",
Short: "Manage attachments",
Long: `List, download, and upload attachments.`,
}
cmd.AddCommand(attachmentListCmd())
cmd.AddCommand(attachmentDownloadCmd())
cmd.AddCommand(attachmentUploadCmd())
return cmd
}
func attachmentListCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "list",
Short: "List all attachments",
RunE: func(cmd *cobra.Command, args []string) error {
manager := attachment.NewAttachmentManager()
ids, err := manager.List()
if err != nil {
return fmt.Errorf("failed to list attachments: %w", err)
}
if len(ids) == 0 {
fmt.Println("No attachments found")
return nil
}
fmt.Println("Attachments:")
for _, id := range ids {
fmt.Printf(" - %s\n", id)
}
return nil
},
}
return cmd
}
func attachmentDownloadCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "download <attachment-id> [output-dir]",
Short: "Download an attachment",
RunE: func(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return fmt.Errorf("attachment ID is required")
}
id := args[0]
outputDir := "."
if len(args) > 1 {
outputDir = args[1]
}
manager := attachment.NewAttachmentManager()
data, err := manager.Get(id)
if err != nil {
return fmt.Errorf("failed to get attachment: %w", err)
}
if err := manager.Download(id, id, outputDir); err != nil {
return fmt.Errorf("failed to download attachment: %w", err)
}
fmt.Printf("Downloaded attachment %s to %s\n", id, outputDir)
fmt.Printf("Size: %d bytes\n", len(data))
return nil
},
}
return cmd
}
func attachmentUploadCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "upload <attachment-id> <file-path>",
Short: "Upload an attachment",
RunE: func(cmd *cobra.Command, args []string) error {
if len(args) < 2 {
return fmt.Errorf("attachment ID and file path are required")
}
id := args[0]
filePath := args[1]
file, err := os.Open(filePath)
if err != nil {
return fmt.Errorf("failed to open file: %w", err)
}
defer file.Close()
manager := attachment.NewAttachmentManager()
if err := manager.Upload(id, file.Name(), file); err != nil {
return fmt.Errorf("failed to upload attachment: %w", err)
}
info, _ := file.Stat()
fmt.Printf("Uploaded attachment %s (%s, %d bytes)\n", id, file.Name(), info.Size())
return nil
},
}
return cmd
}
func readAll(r io.Reader) ([]byte, error) {
return io.ReadAll(r)
}