Added node docx-to-page example

This commit is contained in:
Dan Brown 2021-06-05 00:28:08 +01:00
commit 04b4fca337
Signed by: danb
GPG key ID: 46D9F943C24A2EF9

View 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
View 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=="
}
}
}

View 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"
}
}

View 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
```