diff --git a/config.js b/config.js index 205d633..25c7f7f 100644 --- a/config.js +++ b/config.js @@ -1,18 +1,76 @@ // load configuraton from .env file (if exists) require('dotenv').config() +const convict = require('convict') -let config = { - 'webdav:server_url': process.env.WEBDAV_SERVER_URL, - 'webdav:username': process.env.WEBDAV_USERNAME, - 'webdav:password': process.env.WEBDAV_PASSWORD, - 'webdav:path_prefix': process.env.WEBDAV_PATH_PREFIX, - 'webdav:uploaded_path_prefix': process.env.WEBDAV_UPlOADED_PATH_PREFIX, - 'webdav:use_digest': process.env.WEBDAV_USE_DIGEST, - 'ghost:url': process.env.GHOST_URL, - 'ghost:version': process.env.GHOST_VERSION, - 'ghost:admin_key': process.env.GHOST_ADMIN_KEY, - 'scissor:path': process.env.SEPARATOR_IMAGE, -} +let config = convict({ + webdav: { + server_url: { + doc: 'WebDAV server URL (eg. https://myhost.com:2078)', + format: 'url', + env: 'WEBDAV_SERVER_URL', + default: null, + }, + username: { + doc: 'Username for WebDAV server', + format: 'String', + env: 'WEBDAV_USERNAME', + default: null, + }, + password: { + doc: 'Password for WebDAV server', + format: 'String', + env: 'WEBDAV_PASSWORD', + default: null, + sensitive: true, + }, + path_prefix: { + doc: 'Where to upload files (eg. /seance-uploads)', + format: 'String', + env: 'WEBDAV_PATH_PREFIX', + default: null, + }, + uploaded_path_prefix: { + doc: 'URL where files are uploaded (eg. https://mysitem.com/media)', + format: 'url', + env: 'WEBDAV_UPLOADED_PATH_PREFIX', + default: null, + }, + use_digest: { + doc: 'Whether to use digest authentication', + format: 'Boolean', + env: 'WEBDAV_USE_DIGEST', + default: false, + } + }, + ghost: { + url: { + doc: 'URL of Ghost installation', + format: 'url', + env: 'GHOST_URL', + default: null, + }, + version: { + format: 'String', + env: 'GHOST_VERSION', + default: 'v2', + }, + admin_key: { + doc: 'Admin API key for Ghost', + format: 'String', + env: 'GHOST_ADMIN_KEY', + default: null, + sensitive: true, + } + }, + scissors: { + doc: 'Separator image (for comparison)', + format: '*', // TODO: validate by checking path + env: 'SEPARATOR_IMAGE', + default: null, + } +}) -module.exports = config +config.validate() + +module.exports = config.getProperties() diff --git a/functions.js b/functions.js index 864c679..e45e174 100644 --- a/functions.js +++ b/functions.js @@ -14,9 +14,9 @@ const config = require('./config') const MEDIUM_IMG_CDN = 'https://miro.medium.com/fit/c/' const ghostAdmin = new GhostAdminAPI({ - url: config['ghost:url'], - version: config['ghost:version'], - key: config['ghost:admin_key'], + url: config.ghost.url, + version: config.ghost.version, + key: config.ghost.admin_key, }) /** @@ -113,11 +113,11 @@ const pushToGhost = async (postSlug) => { ) // Path where WebDAV files will be placed (eg. https://example.com:2078) - const davPath = path.join(config['webdav:path_prefix'], uploadPath) + const davPath = path.join(config.webdav.path_prefix, uploadPath) // Public path to upload those files (eg. https://media.example.com/uploads) // We'll do it directly since path.join mangles the protocol - const uploadedPath = config['webdav:uploaded_path_prefix'] + '/' + uploadPath + const uploadedPath = config.webdav.uploaded_path_prefix + '/' + uploadPath // load metadata file console.debug('Loading metadata') @@ -257,7 +257,7 @@ const checkScissors = async (imagePath) => { // Decide "separator" image // If set, images matching this will be ignored and replaced // with a horizontal-rule ("---" in markdown) instead. - let scissors = config['scissor:path'] + let scissors = config.scissors // if scissors not set, return false // (it's never a scissors since it never matches) @@ -317,7 +317,7 @@ const generateUserData = async (mediumUsername, email) => { console.log("Uploading to server") - await uploadDav(path.join(config['webdav:path_prefix'],'avatars'), + await uploadDav(path.join(config.webdav.path_prefix,'avatars'), filePath) // Generate Ghost JSON @@ -331,7 +331,7 @@ const generateUserData = async (mediumUsername, email) => { bio: json.payload.user.bio, email: email, name: json.payload.user.name, - profile_image: config['webdav:uploaded_path_prefix'] + '/avatars/' + fileName + profile_image: config.webdav.uploaded_path_prefix + '/avatars/' + fileName } ] }, @@ -348,8 +348,8 @@ const createDirIfNotExist = async (client, folder) => { // recursively create subfolders if they don't exist. //safety: don't touch directories outside WEBDAV_PATH_PREFIX - if (!folder.startsWith(config['webdav:path_prefix'])) { - throw new Error(`Cannot create directories outside ${config['webdav:path_prefix']}`) + if (!folder.startsWith(config.webdav.path_prefix)) { + throw new Error(`Cannot create directories outside ${config.webdav.path_prefix}`) } // check the folder @@ -410,11 +410,11 @@ const uploadDav = async (dirPath, filePath) => { // connect to webdav client = createClient( - config['webdav:server_url'], + config.webdav.server_url, { - username: config['webdav:username'], - password: config['webdav:password'], - digest: config['webdav:use_digest'] == 'true' + username: config.webdav.username, + password: config.webdav.password, + digest: config.webdav.use_digest }) // create directory if not exists diff --git a/index.js b/index.js index fda4398..99e7115 100755 --- a/index.js +++ b/index.js @@ -59,7 +59,7 @@ program.command('webdav-test ') // decide path current_date = new Date(); var dir_path = path.join( - config['webdav:path_prefix'], + config.webdav.path_prefix, current_date.getUTCFullYear().toString(), current_date.getUTCMonth().toString(), 'test' // TODO: replace with article slug diff --git a/package.json b/package.json index 5d47d63..57117f3 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ "dependencies": { "@tryghost/admin-api": "^1.0.1", "commander": "^3.0.2", + "convict": "^5.2.0", "dotenv": "^8.2.0", "markdown": "^0.5.0", "mediumexporter": "github:badrihippo/mediumexporter#seance-latest", diff --git a/yarn.lock b/yarn.lock index 1def1f5..19c500e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -75,6 +75,11 @@ buffer-equal-constant-time@1.0.1: resolved "https://registry.yarnpkg.com/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz#f8e71132f7ffe6e01a5c9697a4c6f3e48d5cc819" integrity sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk= +camelcase@^5.0.0: + version "5.3.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" + integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== + canvas@^2.0.0-alpha.6: version "2.6.1" resolved "https://registry.yarnpkg.com/canvas/-/canvas-2.6.1.tgz#0d087dd4d60f5a5a9efa202757270abea8bef89e" @@ -126,6 +131,17 @@ console-control-strings@^1.0.0, console-control-strings@~1.1.0: resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4= +convict@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/convict/-/convict-5.2.0.tgz#4c01fa06885b8c4a4ffc98b7de43222fe6c876dc" + integrity sha512-C3cdUwo47cCikZNzu5Vv8AL0MuXVVeg9t/Gyr9qyK5ZpCjOkMPmJ85KUF3CowNeSfj4UtztHxS+hoO9wGRh6kg== + dependencies: + json5 "2.1.0" + lodash.clonedeep "4.5.0" + moment "2.24.0" + validator "11.1.0" + yargs-parser "13.0.0" + core-util-is@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" @@ -145,6 +161,11 @@ debug@^3.2.6: dependencies: ms "^2.1.1" +decamelize@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" + integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= + decompress-response@^4.2.0: version "4.2.1" resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-4.2.1.tgz#414023cc7a302da25ce2ec82d0d5238ccafd8986" @@ -385,6 +406,13 @@ isarray@~1.0.0: resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= +json5@2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.1.0.tgz#e7a0c62c48285c628d20a10b85c89bb807c32850" + integrity sha512-8Mh9h6xViijj36g7Dxi+Y4S6hNGV96vcJZr/SrlHh1LR/pEn/8j/+qIBbs44YKl69Lrfctp4QD+AdWLTMqEZAQ== + dependencies: + minimist "^1.2.0" + jsonwebtoken@^8.4.0: version "8.5.1" resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz#00e71e0b8df54c2121a1f26137df2280673bcc0d" @@ -418,6 +446,11 @@ jws@^3.2.2: jwa "^1.4.1" safe-buffer "^5.0.1" +lodash.clonedeep@4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" + integrity sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8= + lodash.includes@^4.3.0: version "4.3.0" resolved "https://registry.yarnpkg.com/lodash.includes/-/lodash.includes-4.3.0.tgz#60bb98a87cb923c68ca1e51325483314849f553f" @@ -531,6 +564,11 @@ mkdirp@^0.5.0, mkdirp@^0.5.1: dependencies: minimist "0.0.8" +moment@2.24.0: + version "2.24.0" + resolved "https://registry.yarnpkg.com/moment/-/moment-2.24.0.tgz#0d055d53f5052aa653c9f6eb68bb5d12bf5c2b5b" + integrity sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg== + ms@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" @@ -939,6 +977,11 @@ util.promisify@~1.0.0: define-properties "^1.1.2" object.getownpropertydescriptors "^2.0.3" +validator@11.1.0: + version "11.1.0" + resolved "https://registry.yarnpkg.com/validator/-/validator-11.1.0.tgz#ac18cac42e0aa5902b603d7a5d9b7827e2346ac4" + integrity sha512-qiQ5ktdO7CD6C/5/mYV4jku/7qnqzjrxb3C/Q5wR3vGGinHTgJZN/TdFT3ZX4vXhX2R1PXx42fB1cn5W+uJ4lg== + webdav@^2.10.0: version "2.10.0" resolved "https://registry.yarnpkg.com/webdav/-/webdav-2.10.0.tgz#96601aafa0a16ad1410dc734285817efbc7f101d" @@ -984,3 +1027,11 @@ yallist@^3.0.0, yallist@^3.0.3: version "3.1.1" resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== + +yargs-parser@13.0.0: + version "13.0.0" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.0.0.tgz#3fc44f3e76a8bdb1cc3602e860108602e5ccde8b" + integrity sha512-w2LXjoL8oRdRQN+hOyppuXs+V/fVAYtpcrRxZuF7Kt/Oc+Jr2uAcVntaUTNT6w5ihoWfFDpNY8CPx1QskxZ/pw== + dependencies: + camelcase "^5.0.0" + decamelize "^1.2.0"