Added node docx-to-page example
This commit is contained in:
parent 19f9a5bcf2
commit 04b4fca337
4 changed files with 404 additions and 0 deletions
84 node-docx-to-page/index.js Normal file
84
node-docx-to-page/index.js Normal file | @ -0,0 +1,84 @@ | |||
// Libraries used | ||||
const fs = require('fs'); | ||||
const path = require('path'); | ||||
const axios = require('axios'); | ||||
const mammoth = require('mammoth'); | ||||
| ||||
// BookStack API variables | ||||
// Uses values on the environment unless hardcoded | ||||
// To hardcode, add values to the empty strings in the below. | ||||
const bookStackConfig = { | ||||
base_url: '' || process.env.BS_URL, | ||||
token_id: '' || process.env.BS_TOKEN_ID, | ||||
token_secret: '' || process.env.BS_TOKEN_SECRET, | ||||
}; | ||||
| ||||
// Script Logic | ||||
//////////////// | ||||
| ||||
// Check arguments provided | ||||
if (process.argv.length < 4) { | ||||
console.error('Both <docx_file> and <book_slug> arguments need to be provided'); | ||||
return; | ||||
} | ||||
| ||||
// Get arguments passed via command | ||||
const [_exec, _script, docxFile, bookSlug] = process.argv; | ||||
| ||||
// Check the docx file exists | ||||
if (!fs.existsSync(docxFile)) { | ||||
console.error(`Provided docx file "${docxFile}" could not be found`); | ||||
return; | ||||
} | ||||
| ||||
// Create an axios instance for our API | ||||
const api = axios.create({ | ||||
baseURL: bookStackConfig.base_url.replace(/\/$/, '') + '/api/', | ||||
timeout: 5000, | ||||
headers: { 'Authorization' : `Token ${bookStackConfig.token_id}:${bookStackConfig.token_secret}` }, | ||||
}); | ||||
| ||||
// Wrap the rest of our code in an async function so we can await within. | ||||
(async function() { | ||||
| ||||
// Fetch the related book to ensure it exists | ||||
const {data: bookSearch} = await api.get(`/books?filter[slug]=${encodeURIComponent(bookSlug)}`); | ||||
if (bookSearch.data.length === 0) { | ||||
console.error(`Book with a slug of "${bookSlug}" could not be found`); | ||||
return; | ||||
} | ||||
const book = bookSearch.data[0]; | ||||
| ||||
// Convert our document | ||||
const {value: html, messages} = await mammoth.convertToHtml({path: docxFile}); | ||||
| ||||
// Create a name from our document file name | ||||
let {name} = path.parse(docxFile); | ||||
name = name.replace(/[-_]/g, ' '); | ||||
| ||||
// Upload our page | ||||
const {data: page} = await api.post('/pages', { | ||||
book_id: book.id, | ||||
name, | ||||
html, | ||||
}); | ||||
| ||||
// Output the results | ||||
console.info(`File converted and created as a page.`); | ||||
console.info(` - Page ID: ${page.id}`); | ||||
console.info(` - Page Name: ${page.name}`); | ||||
console.info(`====================================`); | ||||
console.info(`Conversion occurred with ${messages.length} message(s):`); | ||||
for (const message of messages) { | ||||
console.warn(`[${message.type}] ${message.message}`); | ||||
} | ||||
| ||||
})().catch(err => { | ||||
// Handle API errors | ||||
if (err.response) { | ||||
console.error(`Request failed with status ${err.response.status} [${err.response.statusText}]`); | ||||
return; | ||||
} | ||||
// Output all other errors | ||||
console.error(err) | ||||
}); |
258 node-docx-to-page/package-lock.json generated Normal file
258
node-docx-to-page/package-lock.json generated Normal file | @ -0,0 +1,258 @@ | |||
{ | ||||
"name": "docx-to-page", | ||||
"version": "1.0.0", | ||||
"lockfileVersion": 2, | ||||
"requires": true, | ||||
"packages": { | ||||
"": { | ||||
"name": "docx-to-page", | ||||
"version": "1.0.0", | ||||
"license": "MIT", | ||||
"dependencies": { | ||||
"axios": "^0.21.1", | ||||
"mammoth": "^1.4.17" | ||||
} | ||||
}, | ||||
"node_modules/argparse": { | ||||
"version": "1.0.10", | ||||
"resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", | ||||
"integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", | ||||
"dependencies": { | ||||
"sprintf-js": "~1.0.2" | ||||
} | ||||
}, | ||||
"node_modules/axios": { | ||||
"version": "0.21.1", | ||||
"resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz", | ||||
"integrity": "sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==", | ||||
"dependencies": { | ||||
"follow-redirects": "^1.10.0" | ||||
} | ||||
}, | ||||
"node_modules/bluebird": { | ||||
"version": "3.4.7", | ||||
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.4.7.tgz", | ||||
"integrity": "sha1-9y12C+Cbf3bQjtj66Ysomo0F+rM=" | ||||
}, | ||||
"node_modules/dingbat-to-unicode": { | ||||
"version": "1.0.1", | ||||
"resolved": "https://registry.npmjs.org/dingbat-to-unicode/-/dingbat-to-unicode-1.0.1.tgz", | ||||
"integrity": "sha512-98l0sW87ZT58pU4i61wa2OHwxbiYSbuxsCBozaVnYX2iCnr3bLM3fIes1/ej7h1YdOKuKt/MLs706TVnALA65w==" | ||||
}, | ||||
"node_modules/duck": { | ||||
"version": "0.1.12", | ||||
"resolved": "https://registry.npmjs.org/duck/-/duck-0.1.12.tgz", | ||||
"integrity": "sha512-wkctla1O6VfP89gQ+J/yDesM0S7B7XLXjKGzXxMDVFg7uEn706niAtyYovKbyq1oT9YwDcly721/iUWoc8MVRg==", | ||||
"dependencies": { | ||||
"underscore": "^1.13.1" | ||||
} | ||||
}, | ||||
"node_modules/follow-redirects": { | ||||
"version": "1.14.1", | ||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.1.tgz", | ||||
"integrity": "sha512-HWqDgT7ZEkqRzBvc2s64vSZ/hfOceEol3ac/7tKwzuvEyWx3/4UegXh5oBOIotkGsObyk3xznnSRVADBgWSQVg==", | ||||
"funding": [ | ||||
{ | ||||
"type": "individual", | ||||
"url": "https://github.com/sponsors/RubenVerborgh" | ||||
} | ||||
], | ||||
"engines": { | ||||
"node": ">=4.0" | ||||
}, | ||||
"peerDependenciesMeta": { | ||||
"debug": { | ||||
"optional": true | ||||
} | ||||
} | ||||
}, | ||||
"node_modules/jszip": { | ||||
"version": "2.5.0", | ||||
"resolved": "https://registry.npmjs.org/jszip/-/jszip-2.5.0.tgz", | ||||
"integrity": "sha1-dET9hVHd8+XacZj+oMkbyDCMwnQ=", | ||||
"dependencies": { | ||||
"pako": "~0.2.5" | ||||
} | ||||
}, | ||||
"node_modules/lop": { | ||||
"version": "0.4.1", | ||||
"resolved": "https://registry.npmjs.org/lop/-/lop-0.4.1.tgz", | ||||
"integrity": "sha512-9xyho9why2A2tzm5aIcMWKvzqKsnxrf9B5I+8O30olh6lQU8PH978LqZoI4++37RBgS1Em5i54v1TFs/3wnmXQ==", | ||||
"dependencies": { | ||||
"duck": "^0.1.12", | ||||
"option": "~0.2.1", | ||||
"underscore": "^1.13.1" | ||||
} | ||||
}, | ||||
"node_modules/mammoth": { | ||||
"version": "1.4.17", | ||||
"resolved": "https://registry.npmjs.org/mammoth/-/mammoth-1.4.17.tgz", | ||||
"integrity": "sha512-/YTeOtKsrPWwFt6dufmqXyJEq4En1GXloU4cYU7x4nnIa51H6AIRelkSba/m+6Emg7rZwIxGxa1hg7S3dK8M9Q==", | ||||
"dependencies": { | ||||
"argparse": "~1.0.3", | ||||
"bluebird": "~3.4.0", | ||||
"dingbat-to-unicode": "^1.0.1", | ||||
"jszip": "~2.5.0", | ||||
"lop": "^0.4.1", | ||||
"path-is-absolute": "^1.0.0", | ||||
"sax": "~1.1.1", | ||||
"underscore": "^1.13.1", | ||||
"xmlbuilder": "^10.0.0" | ||||
}, | ||||
"bin": { | ||||
"mammoth": "bin/mammoth" | ||||
} | ||||
}, | ||||
"node_modules/option": { | ||||
"version": "0.2.4", | ||||
"resolved": "https://registry.npmjs.org/option/-/option-0.2.4.tgz", | ||||
"integrity": "sha1-/Udc35jcq7PLOXo7pShP60Xtv+Q=" | ||||
}, | ||||
"node_modules/pako": { | ||||
"version": "0.2.9", | ||||
"resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz", | ||||
"integrity": "sha1-8/dSL073gjSNqBYbrZ7P1Rv4OnU=" | ||||
}, | ||||
"node_modules/path-is-absolute": { | ||||
"version": "1.0.1", | ||||
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", | ||||
"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", | ||||
"engines": { | ||||
"node": ">=0.10.0" | ||||
} | ||||
}, | ||||
"node_modules/sax": { | ||||
"version": "1.1.6", | ||||
"resolved": "https://registry.npmjs.org/sax/-/sax-1.1.6.tgz", | ||||
"integrity": "sha1-XWFr6KXmB9VOEUr65Vt+ry/MMkA=" | ||||
}, | ||||
"node_modules/sprintf-js": { | ||||
"version": "1.0.3", | ||||
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", | ||||
"integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" | ||||
}, | ||||
"node_modules/underscore": { | ||||
"version": "1.13.1", | ||||
"resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.1.tgz", | ||||
"integrity": "sha512-hzSoAVtJF+3ZtiFX0VgfFPHEDRm7Y/QPjGyNo4TVdnDTdft3tr8hEkD25a1jC+TjTuE7tkHGKkhwCgs9dgBB2g==" | ||||
}, | ||||
"node_modules/xmlbuilder": { | ||||
"version": "10.1.1", | ||||
"resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-10.1.1.tgz", | ||||
"integrity": "sha512-OyzrcFLL/nb6fMGHbiRDuPup9ljBycsdCypwuyg5AAHvyWzGfChJpCXMG88AGTIMFhGZ9RccFN1e6lhg3hkwKg==", | ||||
"engines": { | ||||
"node": ">=4.0" | ||||
} | ||||
} | ||||
}, | ||||
"dependencies": { | ||||
"argparse": { | ||||
"version": "1.0.10", | ||||
"resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", | ||||
"integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", | ||||
"requires": { | ||||
"sprintf-js": "~1.0.2" | ||||
} | ||||
}, | ||||
"axios": { | ||||
"version": "0.21.1", | ||||
"resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz", | ||||
"integrity": "sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==", | ||||
"requires": { | ||||
"follow-redirects": "^1.10.0" | ||||
} | ||||
}, | ||||
"bluebird": { | ||||
"version": "3.4.7", | ||||
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.4.7.tgz", | ||||
"integrity": "sha1-9y12C+Cbf3bQjtj66Ysomo0F+rM=" | ||||
}, | ||||
"dingbat-to-unicode": { | ||||
"version": "1.0.1", | ||||
"resolved": "https://registry.npmjs.org/dingbat-to-unicode/-/dingbat-to-unicode-1.0.1.tgz", | ||||
"integrity": "sha512-98l0sW87ZT58pU4i61wa2OHwxbiYSbuxsCBozaVnYX2iCnr3bLM3fIes1/ej7h1YdOKuKt/MLs706TVnALA65w==" | ||||
}, | ||||
"duck": { | ||||
"version": "0.1.12", | ||||
"resolved": "https://registry.npmjs.org/duck/-/duck-0.1.12.tgz", | ||||
"integrity": "sha512-wkctla1O6VfP89gQ+J/yDesM0S7B7XLXjKGzXxMDVFg7uEn706niAtyYovKbyq1oT9YwDcly721/iUWoc8MVRg==", | ||||
"requires": { | ||||
"underscore": "^1.13.1" | ||||
} | ||||
}, | ||||
"follow-redirects": { | ||||
"version": "1.14.1", | ||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.1.tgz", | ||||
"integrity": "sha512-HWqDgT7ZEkqRzBvc2s64vSZ/hfOceEol3ac/7tKwzuvEyWx3/4UegXh5oBOIotkGsObyk3xznnSRVADBgWSQVg==" | ||||
}, | ||||
"jszip": { | ||||
"version": "2.5.0", | ||||
"resolved": "https://registry.npmjs.org/jszip/-/jszip-2.5.0.tgz", | ||||
"integrity": "sha1-dET9hVHd8+XacZj+oMkbyDCMwnQ=", | ||||
"requires": { | ||||
"pako": "~0.2.5" | ||||
} | ||||
}, | ||||
"lop": { | ||||
"version": "0.4.1", | ||||
"resolved": "https://registry.npmjs.org/lop/-/lop-0.4.1.tgz", | ||||
"integrity": "sha512-9xyho9why2A2tzm5aIcMWKvzqKsnxrf9B5I+8O30olh6lQU8PH978LqZoI4++37RBgS1Em5i54v1TFs/3wnmXQ==", | ||||
"requires": { | ||||
"duck": "^0.1.12", | ||||
"option": "~0.2.1", | ||||
"underscore": "^1.13.1" | ||||
} | ||||
}, | ||||
"mammoth": { | ||||
"version": "1.4.17", | ||||
"resolved": "https://registry.npmjs.org/mammoth/-/mammoth-1.4.17.tgz", | ||||
"integrity": "sha512-/YTeOtKsrPWwFt6dufmqXyJEq4En1GXloU4cYU7x4nnIa51H6AIRelkSba/m+6Emg7rZwIxGxa1hg7S3dK8M9Q==", | ||||
"requires": { | ||||
"argparse": "~1.0.3", | ||||
"bluebird": "~3.4.0", | ||||
"dingbat-to-unicode": "^1.0.1", | ||||
"jszip": "~2.5.0", | ||||
"lop": "^0.4.1", | ||||
"path-is-absolute": "^1.0.0", | ||||
"sax": "~1.1.1", | ||||
"underscore": "^1.13.1", | ||||
"xmlbuilder": "^10.0.0" | ||||
} | ||||
}, | ||||
"option": { | ||||
"version": "0.2.4", | ||||
"resolved": "https://registry.npmjs.org/option/-/option-0.2.4.tgz", | ||||
"integrity": "sha1-/Udc35jcq7PLOXo7pShP60Xtv+Q=" | ||||
}, | ||||
"pako": { | ||||
"version": "0.2.9", | ||||
"resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz", | ||||
"integrity": "sha1-8/dSL073gjSNqBYbrZ7P1Rv4OnU=" | ||||
}, | ||||
"path-is-absolute": { | ||||
"version": "1.0.1", | ||||
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", | ||||
"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" | ||||
}, | ||||
"sax": { | ||||
"version": "1.1.6", | ||||
"resolved": "https://registry.npmjs.org/sax/-/sax-1.1.6.tgz", | ||||
"integrity": "sha1-XWFr6KXmB9VOEUr65Vt+ry/MMkA=" | ||||
}, | ||||
"sprintf-js": { | ||||
"version": "1.0.3", | ||||
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", | ||||
"integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" | ||||
}, | ||||
"underscore": { | ||||
"version": "1.13.1", | ||||
"resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.1.tgz", | ||||
"integrity": "sha512-hzSoAVtJF+3ZtiFX0VgfFPHEDRm7Y/QPjGyNo4TVdnDTdft3tr8hEkD25a1jC+TjTuE7tkHGKkhwCgs9dgBB2g==" | ||||
}, | ||||
"xmlbuilder": { | ||||
"version": "10.1.1", | ||||
"resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-10.1.1.tgz", | ||||
"integrity": "sha512-OyzrcFLL/nb6fMGHbiRDuPup9ljBycsdCypwuyg5AAHvyWzGfChJpCXMG88AGTIMFhGZ9RccFN1e6lhg3hkwKg==" | ||||
} | ||||
} | ||||
} |
16 node-docx-to-page/package.json Normal file
16
node-docx-to-page/package.json Normal file | @ -0,0 +1,16 @@ | |||
{ | ||||
"name": "docx-to-page", | ||||
"version": "1.0.0", | ||||
"description": "This script will take a docx file, attempt to convert it to a BookStack suitable format, then upload it into a BookStack book via the API.", | ||||
"main": "index.js", | ||||
"scripts": { | ||||
"test": "echo \"Error: no test specified\" && exit 1" | ||||
}, | ||||
"keywords": [], | ||||
"author": "Dan Brown", | ||||
"license": "MIT", | ||||
"dependencies": { | ||||
"axios": "^0.21.1", | ||||
"mammoth": "^1.4.17" | ||||
} | ||||
} |
46 node-docx-to-page/readme.md Normal file
46
node-docx-to-page/readme.md Normal file | @ -0,0 +1,46 @@ | |||
# Convert docx to Page | ||||
| ||||
This script will take a docx file, | ||||
attempt to convert it to a BookStack suitable format, then upload | ||||
it into a BookStack book via the API. | ||||
| ||||
This is a simplistic example of a NodeJS script. You will likely want to | ||||
alter and extend this script to suit your use-case. | ||||
| ||||
## Requirements | ||||
| ||||
You will need NodeJS installed (Tested on v14, may work on earlier versions). | ||||
Images can be converted and uploaded via this but this requires Base64 image support | ||||
by BookStack so you'll need to be using BookStack v21.05.1 or greater. | ||||
| ||||
## Running | ||||
| ||||
First, download all the files in the same directory as this readme to a folder on your system | ||||
and run the below from within that directory. | ||||
| ||||
```bash | ||||
# Install NodeJS dependencies via NPM | ||||
npm install | ||||
| ||||
# Setup | ||||
# ALTERNATIVELY: Open the script and add to the empty strings in the variables at the top. | ||||
export BS_URL=https://bookstack.example.com # Set to be your BookStack base URL | ||||
export BS_TOKEN_ID=abc123 # Set to be your API token_id | ||||
export BS_TOKEN_SECRET=123abc # Set to be your API token_secret | ||||
| ||||
# Running the script | ||||
node index.js <docx_file> <book_slug> | ||||
``` | ||||
| ||||
- `<docx_file>` - File you want to convert & upload. | ||||
- `<book_slug>` - The unique book identifier shown in the URL bar within BookStack (Autogenerated from the name). | ||||
- For example: | ||||
- Book URL: https://example.com/books/bookstack-user-guide | ||||
- Book Slug: bookstack-user-guide | ||||
| ||||
## Examples | ||||
| ||||
```bash | ||||
# Convert the 'my_content.docx' file and upload to the Book with slug 'bookstack-user-guide' | ||||
node index.js my_content.docx bookstack-user-guide | ||||
``` |
Loading…
Add table
Add a link
Reference in a new issue