Skip to content

Instantly share code, notes, and snippets.

@castodius
Last active April 10, 2024 19:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save castodius/84c5ec49cceca5eb9a667dec3058364e to your computer and use it in GitHub Desktop.
Save castodius/84c5ec49cceca5eb9a667dec3058364e to your computer and use it in GitHub Desktop.
Exporting Confluence page as PDF using NodeJS
import { writeFileSync } from 'fs'
/**
* Example of how to export a Confluence Page as a PDF and writing it to disk
* The code has poor error handling, but is hopefully easy to understand
*
* The basic steps are:
* - Load PDF export page
* - Find task id
* - Wait for task to complete and get result path in return
* - Get task result which is a signed AWS S3 url allowing you to download the PDF
* - Call the S3 url and do whatever you want with the returned value
*
* Logic was extracted from https://github.com/atlassian-api/atlassian-python-api/blob/master/atlassian/confluence.py
*/
const confluenceDomain = ''
const username = ''
// password probably works as well
const apiToken = ''
// id of page you want to export as PDF, found in the url of the page itself. Always 10 digits from what I can tell
const pageId = ''
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms))
const waitForTaskCompletion = async (taskId) => {
while (true) {
await sleep(2000)
const progress = await fetch(`${apiDomain}/wiki/services/api/v1/task/${taskId}/progress`, { headers })
.then(res => res.json())
console.log(progress)
switch (progress.state) {
case 'PDF_GENERATED':
case 'IN_PROGRESS':
break
case 'UPLOADED_TO_S3':
return progress.result
default:
throw new Error('Unknown state')
}
}
}
const apiDomain = `https://${confluenceDomain}.atlassian.net`
const headers = new Headers()
headers.append('Authorization', `Basic ${Buffer.from(username + ':' + apiToken).toString('base64')})}`)
headers.append('X-Atlassian-Token', 'no-check')
// This serves two purposes. It triggers the PDF generation and returns the HTML page which contains the task id
const pdfDownloadPage = await fetch(`${apiDomain}/wiki/spaces/flyingpdf/pdfpageexport.action?pageId=${pageId}`, { headers })
.then(res => res.text())
// The line we are looking for is of format " <meta name="ajs-taskId" content="54b4d158-2a34-4bf4-acc1-58da7f27b3dd">"
const taskId = pdfDownloadPage
.split('\n')
.find(line => line.includes('ajs-taskId'))
.match(/[a-f0-9]{8}-[a-f0-9-]+/)[0]
const taskResult = await waitForTaskCompletion(taskId)
const downloadUrl = await fetch(`${apiDomain}${taskResult}`, { headers })
.then(res => res.text())
const pdfBuffer = await fetch(downloadUrl)
.then(res => res.arrayBuffer())
writeFileSync('./page.pdf', Buffer.from(pdfBuffer))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment