b04823e67b
Persist uploaded files to {data_dir}/documents/{content_hash}{ext} after
successful ingestion. Add GET /documents/{id}/file endpoint for retrieval,
delete stored files on document deletion, and add `kb export` client command.
Includes schema migration, tests, and spec updates.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
75 lines
1.6 KiB
Go
75 lines
1.6 KiB
Go
package cmd
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
"mime"
|
|
"os"
|
|
"path/filepath"
|
|
|
|
"github.com/kb-search/kb/internal/api"
|
|
"github.com/spf13/cobra"
|
|
)
|
|
|
|
var exportCmd = &cobra.Command{
|
|
Use: "export <id>",
|
|
Short: "Download original document file",
|
|
Args: cobra.ExactArgs(1),
|
|
RunE: runExport,
|
|
}
|
|
|
|
func init() {
|
|
exportCmd.Flags().StringP("output", "o", "", "output file path (default: original filename to current directory)")
|
|
rootCmd.AddCommand(exportCmd)
|
|
}
|
|
|
|
func runExport(cmd *cobra.Command, args []string) error {
|
|
client := api.NewClient()
|
|
resp, err := client.Get("/api/v1/documents/" + args[0] + "/file")
|
|
if err != nil {
|
|
fmt.Fprintln(os.Stderr, err)
|
|
os.Exit(1)
|
|
}
|
|
if err := api.CheckError(resp); err != nil {
|
|
fmt.Fprintln(os.Stderr, err)
|
|
os.Exit(1)
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
outPath, _ := cmd.Flags().GetString("output")
|
|
|
|
if outPath == "" {
|
|
// Try to get filename from Content-Disposition header
|
|
cd := resp.Header.Get("Content-Disposition")
|
|
if cd != "" {
|
|
_, params, err := mime.ParseMediaType(cd)
|
|
if err == nil && params["filename"] != "" {
|
|
outPath = params["filename"]
|
|
}
|
|
}
|
|
if outPath == "" {
|
|
outPath = "document-" + args[0]
|
|
}
|
|
}
|
|
|
|
if outPath == "-" {
|
|
_, err := io.Copy(os.Stdout, resp.Body)
|
|
return err
|
|
}
|
|
|
|
outPath = filepath.Clean(outPath)
|
|
f, err := os.Create(outPath)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to create output file: %w", err)
|
|
}
|
|
defer f.Close()
|
|
|
|
n, err := io.Copy(f, resp.Body)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to write file: %w", err)
|
|
}
|
|
|
|
fmt.Fprintf(os.Stderr, "Saved %s (%d bytes)\n", outPath, n)
|
|
return nil
|
|
}
|