1717package confluence
1818
1919import (
20+ "io"
2021 "net/http"
22+ "net/url"
2123 "os"
2224 "time"
23- "net/url"
2425
2526 "github.com/abc-inc/heimdall/cli"
2627 "github.com/abc-inc/heimdall/internal"
@@ -31,20 +32,20 @@ import (
3132
3233type confluenceSearchCfg struct {
3334 confluenceCfg
34- limit int
35- start int
36- cql string
37- expand string
38- exportAsPDF bool
35+ limit int
36+ offset int
37+ cql string
38+ expand string
39+ export string
40+ file string
3941}
4042
4143func NewSearchCmd () * cobra.Command {
4244 cfg := confluenceSearchCfg {confluenceCfg : confluenceCfg {
4345 baseURL : os .Getenv ("CONFLUENCE_API_URL" ),
4446 timeout : 30 * time .Second },
45- expand : "content.body.storage" ,
46- limit : 1 ,
47- exportAsPDF : false ,
47+ expand : "content.body.storage" ,
48+ limit : 10 ,
4849 }
4950
5051 cmd := & cobra.Command {
@@ -60,28 +61,30 @@ func NewSearchCmd() *cobra.Command {
6061 if zerolog .GlobalLevel () == zerolog .TraceLevel || zerolog .GlobalLevel () == zerolog .DebugLevel {
6162 goconfluence .SetDebug (true )
6263 }
64+ if cfg .export == "html" {
65+ cfg .expand = "content.body.view," + cfg .expand
66+ }
6367 s := search (cfg )
64- if cfg .exportAsPDF {
65- exportToPDF (s , cfg )
66- } else if cfg .limit == 1 && len (s .Results ) == 1 {
67- cli .Fmtln (s .Results [0 ])
68+ if cfg .export != "" {
69+ export (s , cfg )
6870 } else {
69- cli .Fmtln (s . Results )
71+ cli .Fmtln (s )
7072 }
7173 },
7274 }
7375
7476 cmd .Flags ().StringVar (& cfg .expand , "expand" , cfg .expand , "Expand specific entities in the returned list" )
77+ cmd .Flags ().StringVarP (& cfg .file , "file" , "O" , cfg .file , "File to save the page to (use '-' for standard output)" )
7578 cmd .Flags ().StringVar (& cfg .cql , "filter" , cfg .cql , "CQL query for searching" )
76- cmd .Flags ().IntVar (& cfg .limit , "limit" , cfg .limit , "Maximum items to return" )
77- cmd .Flags ().IntVar (& cfg .start , "start " , cfg .start , "Starting index of the returned list" )
78- cmd .Flags ().BoolVar (& cfg .exportAsPDF , "export-as-pdf " , cfg .exportAsPDF , "Export search result to a PDF file which will be output to stdout " )
79+ cmd .Flags ().IntVar (& cfg .limit , "limit" , cfg .limit , "Maximum number of items to return" )
80+ cmd .Flags ().IntVar (& cfg .offset , "offset " , cfg .offset , "Starting index of the returned list" )
81+ cmd .Flags ().StringVar (& cfg .export , "export" , cfg .export , "Export page (supported modes: pdf, html) " )
7982 addCommonFlags (cmd , & cfg .confluenceCfg )
8083
8184 cli .AddOutputFlags (cmd , & cfg .OutCfg )
8285 internal .MustNoErr (cmd .MarkFlagRequired ("filter" ))
83- cmd .MarkFlagsMutuallyExclusive ("export-as-pdf " , "limit" )
84- cmd .MarkFlagsMutuallyExclusive ("export-as-pdf " , "output" )
86+ cmd .MarkFlagsMutuallyExclusive ("export" , "limit" )
87+ cmd .MarkFlagsMutuallyExclusive ("export" , "output" )
8588 return cmd
8689}
8790
@@ -90,26 +93,64 @@ func search(cfg confluenceSearchCfg) *goconfluence.Search {
9093 s := internal .Must (api .Search (goconfluence.SearchQuery {
9194 CQL : cfg .cql ,
9295 Limit : cfg .limit ,
93- Start : cfg .start ,
96+ Start : cfg .offset ,
9497 Expand : []string {cfg .expand },
9598 }))
9699
97100 return s
98101}
99102
100- func exportToPDF (s * goconfluence.Search , cfg confluenceSearchCfg ) {
101- internal .MustOkMsgf (1 , len (s .Results ) == 1 , "Error: The result of the search is expected to be 1 result, found %d: PDF not exported." , len (s .Results ))
102- page := s .Results [0 ].Content .ID
103- pdfExportURL := createPDFExportURL (cfg .baseURL , page )
104- req := internal .Must (http .NewRequest ("GET" , pdfExportURL , nil ))
103+ func export (s * goconfluence.Search , cfg confluenceSearchCfg ) {
104+ internal .MustOkMsgf (1 , len (s .Results ) == 1 , "expected 1 page, but found %d" , len (s .Results ))
105+
106+ switch cfg .export {
107+ case "html" :
108+ exportHTML (cfg , s .Results [0 ])
109+ case "pdf" :
110+ exportPDF (cfg , s .Results [0 ])
111+ default :
112+ internal .MustOkMsgf (cfg .export , false , "invalid export format: %s" , cfg .export )
113+ }
114+ }
115+
116+ func exportPDF (cfg confluenceSearchCfg , page goconfluence.Results ) {
117+ u := createPDFExportURL (cfg .baseURL , page .Content .ID )
118+ req := internal .Must (http .NewRequest ("GET" , u , nil ))
105119 api := internal .Must (newClient (cfg .baseURL , cfg .token ))
106- resp := internal .Must (api .Request (req ))
107- internal .Must (os .Stdout .Write (resp ))
120+ data := internal .Must (api .Request (req ))
121+
122+ if cfg .file == "-" {
123+ internal .Must (os .Stdout .Write (data ))
124+ return
125+ }
126+
127+ if cfg .file == "" {
128+ cfg .file = page .Content .Title + ".pdf"
129+ }
130+
131+ internal .MustNoErr (os .WriteFile (cfg .file , data , 0640 ))
132+ }
133+
134+ func exportHTML (cfg confluenceSearchCfg , page goconfluence.Results ) {
135+ data := page .Content .Body .View .Value
136+
137+ if cfg .file == "-" {
138+ internal .Must (os .Stdout .WriteString (data ))
139+ return
140+ }
141+
142+ if cfg .file == "" {
143+ cfg .file = page .Content .Title + ".html"
144+ }
145+
146+ f := internal .Must (os .OpenFile (cfg .file , os .O_RDWR | os .O_CREATE | os .O_TRUNC , 0640 ))
147+ defer func () { _ = f .Close () }()
148+ _ = internal .Must (io .WriteString (f , data ))
108149}
109150
110151func createPDFExportURL (baseURL string , pageID string ) string {
111- u := internal .Must (url .Parse (baseURL ))
152+ u := internal .Must (url .Parse (baseURL ))
112153 u = u .JoinPath ("../../spaces/flyingpdf/pdfpageexport.action" )
113154 u .RawQuery = "pageId=" + pageID
114- return u .String ()
155+ return u .String ()
115156}
0 commit comments