diff --git a/functions.js b/functions.js index 2471beb..e49e97b 100644 --- a/functions.js +++ b/functions.js @@ -2,6 +2,7 @@ const r2 = require('r2') const path = require('path') const fs = require('fs') const getPost = require('mediumexporter').getPost +const { createClient } = require('webdav') /** * function [fetchFromMedium] @@ -86,7 +87,7 @@ async function fetchMediumJSON(mediumUrl) { /** * function [createUser] - * @returns [string] status + * @returns [object] ghost data json */ const generateUserData = async (mediumUsername, email) => { console.debug('Creating: @' + mediumUsername + '(email: ' + email + ')'); @@ -125,9 +126,95 @@ const generateUserData = async (mediumUsername, email) => { return(JSON.stringify(ghostData)) }; +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(process.env.WEBDAV_PATH_PREFIX)) { + throw new Error(`Cannot create directories outside ${process.env.WEBDAV_PATH_PREFIX}`) + } + + // check the folder + await client.stat(folder) + .catch(async (err) => { + if (err.response.status == 404) { + + // it's a 404, so we'll create the directory + console.debug(`Noting missing subdirectory: ${folder}`) + + // first, create the parent directory (if required) + await createDirIfNotExist(client, path.dirname(folder)) + + console.debug(`Creating missing subdirectory: ${folder}`) + // then, create the current directory + await client.createDirectory(folder) + .catch(async (err) => { + if (err.response.status == 405) { // Method Not Allowed + // Maybe the directory's already been created in the meantime? + await client.stat(folder) + .catch((err2) => { + // Bad guess. Panic (and raise the original error) + console.debug(err.toJSON()) + throw err + }) + } else { + // what's this? Panic! + console.debug(err.toJSON()) + throw err + } + }) + } else { + + // it's not a 404; we don't know how to handle this. Panic! + console.debug(err.toJSON()) + throw err + } + }) +} + +/** + * function [createUser] + * @returns [string] status +*/ +const webdavTest = async (filePath) => { + + // connect to webdav + client = createClient( + process.env.WEBDAV_SERVER_URL, + { + username: process.env.WEBDAV_USERNAME, + password: process.env.WEBDAV_PASSWORD, + digest: process.env.WEBDAV_USE_DIGEST == 'true' + }) + + // decide path + current_date = new Date(); + var dir_path = path.join( + process.env.WEBDAV_PATH_PREFIX, + current_date.getUTCFullYear().toString(), + current_date.getUTCMonth().toString(), + 'test' // TODO: replace with article slug + ) + + // create directory if not exists + console.debug(`Loading ${dir_path}`) + await createDirIfNotExist(client, dir_path) + + // upload a file + console.debug('Uploading file') + s = fs.createReadStream(filePath) + .pipe(client.createWriteStream( + path.join(dir_path, path.basename(filePath)) + )) + .on('finish', () => console.debug('Uploaded successfully.')) + + return true +} + module.exports = { fetchFromMedium, pushToGhost, mediumToGhost, generateUserData, + webdavTest } diff --git a/index.js b/index.js index 546ee6b..6ce12e8 100755 --- a/index.js +++ b/index.js @@ -1,5 +1,9 @@ #! /usr/bin/env node +// load configuraton from .env file (if exists) +const dotenv = require('dotenv') +dotenv.config() + const program = require('commander'); const { @@ -7,6 +11,7 @@ const { pushToGhost, mediumToGhost, generateUserData, + webdavTest, } = require ('./functions'); program @@ -48,4 +53,10 @@ program.command('create-user ') console.log(await jsonOut); }); +program.command('webdav-test ') + .description('[test command] upload stuff to WebDAV') + .action(async (file) => { + webdavTest(file); + }); + program.parse(process.argv) diff --git a/package.json b/package.json index 143d259..f7cdaa6 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,9 @@ }, "dependencies": { "commander": "^3.0.2", + "dotenv": "^8.2.0", "mediumexporter": "github:xdamman/mediumexporter#v0.2.0", - "r2": "^2.0.1" + "r2": "^2.0.1", + "webdav": "^2.10.0" } } diff --git a/yarn.lock b/yarn.lock index 10d4191..e2e4e09 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,6 +2,32 @@ # yarn lockfile v1 +axios@^0.19.0: + version "0.19.0" + resolved "https://registry.yarnpkg.com/axios/-/axios-0.19.0.tgz#8e09bff3d9122e133f7b8101c8fbdd00ed3d2ab8" + integrity sha512-1uvKqKQta3KBxIz14F2v06AEHZ/dIoeKfbTRkK1E5oqjDnuEerLmYTgJB5AiQZHJcljpg1TuRzdjDR06qNk0DQ== + dependencies: + follow-redirects "1.5.10" + is-buffer "^2.0.2" + +balanced-match@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" + integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= + +base-64@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/base-64/-/base-64-0.1.0.tgz#780a99c84e7d600260361511c4877613bf24f6bb" + integrity sha1-eAqZyE59YAJgNhURxId2E78k9rs= + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + caseless@^0.12.0: version "0.12.0" resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" @@ -17,6 +43,18 @@ commander@^3.0.2: resolved "https://registry.yarnpkg.com/commander/-/commander-3.0.2.tgz#6837c3fb677ad9933d1cfba42dd14d5117d6b39e" integrity sha512-Gar0ASD4BDyKC4hl4DwHqDrmvjoxWKZigVnAbn5H1owvm4CxCPdb0HQDehwNYMJpla5+M2tPmPARzhtYuwpHow== +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= + +debug@=3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" + integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g== + dependencies: + ms "2.0.0" + define-properties@^1.1.2, define-properties@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" @@ -24,6 +62,11 @@ define-properties@^1.1.2, define-properties@^1.1.3: dependencies: object-keys "^1.0.12" +dotenv@^8.2.0: + version "8.2.0" + resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-8.2.0.tgz#97e619259ada750eea3e4ea3e26bceea5424b16a" + integrity sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw== + entities@^1.1.1: version "1.1.2" resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.2.tgz#bdfa735299664dfafd34529ed4f8522a275fea56" @@ -54,6 +97,13 @@ es-to-primitive@^1.2.0: is-date-object "^1.0.1" is-symbol "^1.0.2" +follow-redirects@1.5.10: + version "1.5.10" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.5.10.tgz#7b7a9f9aea2fdff36786a94ff643ed07f4ff5e2a" + integrity sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ== + dependencies: + debug "=3.1.0" + function-bind@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" @@ -71,6 +121,16 @@ has@^1.0.1, has@^1.0.3: dependencies: function-bind "^1.1.1" +hot-patcher@^0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/hot-patcher/-/hot-patcher-0.5.0.tgz#9d401424585aaf3a91646b816ceff40eb6a916b9" + integrity sha512-2Uu2W0s8+dnqXzdlg0MRsRzPoDCs1wVjOGSyMRRaMzLDX4bgHw6xDYKccsWafXPPxQpkQfEjgW6+17pwcg60bw== + +is-buffer@^2.0.2: + version "2.0.4" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.4.tgz#3e572f23c8411a5cfd9557c849e3665e0b290623" + integrity sha512-Kq1rokWXOPXWuaMAqZiJW4XxsmD9zGx9q4aePabbn3qCRGedtH7Cm+zV8WETitMfu1wdh+Rvd6w5egwSngUX2A== + is-callable@^1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.4.tgz#1e1adf219e1eeb684d691f9d6a05ff0d30a24d75" @@ -110,6 +170,23 @@ is-typedarray@^1.0.0: sanitize-filename "^1.6.1" underscore.string "^3.3.5" +merge@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/merge/-/merge-1.2.1.tgz#38bebf80c3220a8a487b6fcfb3941bb11720c145" + integrity sha512-VjFo4P5Whtj4vsLzsYBu5ayHhoHJ0UqNm7ibvShmbmoz7tGi0vXaoJbGdB+GmDMLUdg8DpQXEIeVDAe8MaABvQ== + +minimatch@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" + integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== + dependencies: + brace-expansion "^1.1.7" + +ms@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= + node-fetch@^2.0.0-alpha.8: version "2.6.0" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.0.tgz#e633456386d4aa55863f676a7ab0daa8fdecb0fd" @@ -133,6 +210,16 @@ object.getownpropertydescriptors@^2.0.3: define-properties "^1.1.2" es-abstract "^1.5.1" +path-posix@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/path-posix/-/path-posix-1.0.0.tgz#06b26113f56beab042545a23bfa88003ccac260f" + integrity sha1-BrJhE/Vr6rBCVFojv6iAA8ysJg8= + +querystringify@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.1.1.tgz#60e5a5fd64a7f8bfa4d2ab2ed6fdf4c85bad154e" + integrity sha512-w7fLxIRCRT7U8Qu53jQnJyPkYZIaR4n5151KMfcJlO/A9397Wxb1amJvROTK6TOnp7PfoAmg/qXiNHI+08jRfA== + r2@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/r2/-/r2-2.0.1.tgz#94cd802ecfce9a622549c8182032d8e4a2b2e612" @@ -142,6 +229,11 @@ r2@^2.0.1: node-fetch "^2.0.0-alpha.8" typedarray-to-buffer "^3.1.2" +requires-port@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" + integrity sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8= + rss-parser@^3.6.2: version "3.7.2" resolved "https://registry.yarnpkg.com/rss-parser/-/rss-parser-3.7.2.tgz#9f5b7d4944d4f7a190b469e31a8353aedb17c052" @@ -205,6 +297,19 @@ underscore.string@^3.3.5: sprintf-js "^1.0.3" util-deprecate "^1.0.2" +url-join@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/url-join/-/url-join-4.0.1.tgz#b642e21a2646808ffa178c4c5fda39844e12cde7" + integrity sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA== + +url-parse@^1.4.7: + version "1.4.7" + resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.4.7.tgz#a8a83535e8c00a316e403a5db4ac1b9b853ae278" + integrity sha512-d3uaVyzDB9tQoSXFvuSUNFibTd9zxd2bkVrDRvF5TmvWWQwqE4lgYJ5m+x1DbecWkw+LK4RNl2CU1hHuOKPVlg== + dependencies: + querystringify "^2.1.1" + requires-port "^1.0.0" + utf8-byte-length@^1.0.1: version "1.0.4" resolved "https://registry.yarnpkg.com/utf8-byte-length/-/utf8-byte-length-1.0.4.tgz#f45f150c4c66eee968186505ab93fcbb8ad6bf61" @@ -223,6 +328,21 @@ util.promisify@~1.0.0: define-properties "^1.1.2" object.getownpropertydescriptors "^2.0.3" +webdav@^2.10.0: + version "2.10.0" + resolved "https://registry.yarnpkg.com/webdav/-/webdav-2.10.0.tgz#96601aafa0a16ad1410dc734285817efbc7f101d" + integrity sha512-wwvVL8IINaQlhHJb2b4z0K1V8nFO5XR+HB+epGfFc2JXqeRRAD68ksq94jl54/JdkHKAr5nlvU9JpW8GML8yBw== + dependencies: + axios "^0.19.0" + base-64 "^0.1.0" + hot-patcher "^0.5.0" + merge "^1.2.1" + minimatch "^3.0.4" + path-posix "^1.0.0" + url-join "^4.0.1" + url-parse "^1.4.7" + xml2js "^0.4.19" + xml2js@^0.4.19: version "0.4.22" resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.22.tgz#4fa2d846ec803237de86f30aa9b5f70b6600de02"