diff --git a/main.go b/main.go index ea144d3..206d02d 100644 --- a/main.go +++ b/main.go @@ -16,6 +16,7 @@ import ( type NodeData struct { Id string Title string + Body string } type Node struct { @@ -23,6 +24,13 @@ type Node struct { Data NodeData } +type Arguments struct { + Baseurl string `arg:"required" help:"Base URL of the Confluence instance (required)"` + Spacekey string `arg:"required" help:"Spacekey to export (required)"` + User string `arg:"required" help:"User used for authentication (required)"` + Token string `arg:"required" help:"Token used for authentication (required)"` +} + func (n *Node) writeIndex(w io.Writer) { tmpl, err := template.New("root").Parse(` {{ define "tree" }} @@ -50,15 +58,15 @@ func (n *Node) writeIndex(w io.Writer) { } } -func (n *Node) writeHTMLFiles() { - if len(n.Children) > 0 { - for _, child := range n.Children { - writeHTML(n) - child.writeHTMLFiles() +func (n *Node) getAllChildren() []*Node { + var children []*Node + for _, child := range n.Children { + children = append(children, child) + if len(child.Children) > 0 { + children = append(children, child.getAllChildren()...) } } - // leaf node - writeHTML(n) + return children } func (n *Node) getChildWithID(id string) (node *Node, hasChild bool) { @@ -81,7 +89,8 @@ func writeHTML(n *Node) { log.Fatalf("Error creating file for ID %v", n.Data.Id) } defer f.Close() - f.Write([]byte(n.Data.Title)) + log.Printf("Writing file %v", f.Name()) + f.Write([]byte(n.Data.Body)) } type spaceResult struct { @@ -159,22 +168,91 @@ type spaceResult struct { } `json:"_links"` } -func getSpaceChildren(url, user, token string) spaceResult { - b64Auth := base64.StdEncoding.EncodeToString([]byte(user + ":" + token)) +type contentResult struct { + ID string `json:"id"` + Type string `json:"type"` + Status string `json:"status"` + Title string `json:"title"` + MacroRenderedOutput struct { + } `json:"macroRenderedOutput"` + Body struct { + View struct { + Value string `json:"value"` + Representation string `json:"representation"` + Expandable struct { + Webresource string `json:"webresource"` + EmbeddedContent string `json:"embeddedContent"` + MediaToken string `json:"mediaToken"` + Content string `json:"content"` + } `json:"_expandable"` + } `json:"view"` + Expandable struct { + Editor string `json:"editor"` + AtlasDocFormat string `json:"atlas_doc_format"` + ExportView string `json:"export_view"` + StyledView string `json:"styled_view"` + Dynamic string `json:"dynamic"` + Storage string `json:"storage"` + Editor2 string `json:"editor2"` + AnonymousExportView string `json:"anonymous_export_view"` + } `json:"_expandable"` + } `json:"body"` + Extensions struct { + Position int `json:"position"` + } `json:"extensions"` + Expandable struct { + ChildTypes string `json:"childTypes"` + Container string `json:"container"` + Metadata string `json:"metadata"` + Operations string `json:"operations"` + SchedulePublishDate string `json:"schedulePublishDate"` + Children string `json:"children"` + Restrictions string `json:"restrictions"` + History string `json:"history"` + Ancestors string `json:"ancestors"` + Version string `json:"version"` + Descendants string `json:"descendants"` + Space string `json:"space"` + } `json:"_expandable"` + Links struct { + Editui string `json:"editui"` + Webui string `json:"webui"` + Context string `json:"context"` + Self string `json:"self"` + Tinyui string `json:"tinyui"` + Collection string `json:"collection"` + Base string `json:"base"` + } `json:"_links"` +} + +func getRequest(args Arguments, url string) ([]byte, error) { + b64Auth := base64.StdEncoding.EncodeToString([]byte(args.User + ":" + args.Token)) client := &http.Client{} req, err := http.NewRequest(http.MethodGet, url, nil) if err != nil { - log.Fatal(err) + return nil, err } req.Header.Add("Authorization", "Basic "+b64Auth) resp, err := client.Do(req) if err != nil { - log.Fatal(err) + return nil, err } if resp.StatusCode != http.StatusOK { - log.Fatalf("Error fetching url: %v, status code: %v", url, resp.StatusCode) + return nil, err + } + if err != nil { + return nil, err } body, err := io.ReadAll(resp.Body) + if err != nil { + return nil, err + } + return body, nil +} + +func getSpaceChildren(args Arguments) spaceResult { + url := args.Baseurl + "/wiki/rest/api/space/" + args.Spacekey + "/content/page?expand=ancestors&limit=9999" + body, err := getRequest(args, url) if err != nil { log.Fatal(err) } @@ -183,7 +261,18 @@ func getSpaceChildren(url, user, token string) spaceResult { return result } -func createPageTree(s *spaceResult) { +func getContentFromID(args Arguments, id string) contentResult { + url := args.Baseurl + "/wiki/rest/api/content/" + id + "?expand=body.view" + body, err := getRequest(args, url) + if err != nil { + log.Fatal(err) + } + var result contentResult + json.Unmarshal(body, &result) + return result +} + +func createPageTree(s *spaceResult) *Node { var parent *Node root := Node{Data: NodeData{Title: "root"}} for _, page := range s.Results { @@ -211,6 +300,15 @@ func createPageTree(s *spaceResult) { n := Node{Data: NodeData{Id: page.ID, Title: page.Title}} parent.addChild(&n) } + return &root +} + +func main() { + var args Arguments + arg.MustParse(&args) + result := getSpaceChildren(args) + root := createPageTree(&result) + fname := "index.html" f, err := os.Create(fname) if err != nil { @@ -218,18 +316,11 @@ func createPageTree(s *spaceResult) { } defer f.Close() root.writeIndex(f) - root.writeHTMLFiles() -} -func main() { - var args struct { - Baseurl string `arg:"required" help:"Base URL of the Confluence instance (required)"` - Spacekey string `arg:"required" help:"Spacekey to export (required)"` - User string `arg:"required" help:"User used for authentication (required)"` - Token string `arg:"required" help:"Token used for authentication (required)"` + pages := root.getAllChildren() + for _, page := range pages { + content := getContentFromID(args, page.Data.Id) + page.Data.Body = content.Body.View.Value + writeHTML(page) } - arg.MustParse(&args) - url := args.Baseurl + "/wiki/rest/api/space/" + args.Spacekey + "/content/page?expand=ancestors&limit=9999" - result := getSpaceChildren(url, args.User, args.Token) - createPageTree(&result) }