diff --git a/README.md b/README.md
index 03edc76..aa420d0 100644
--- a/README.md
+++ b/README.md
@@ -1,34 +1,18 @@
-# roe-base
+# River of Ebooks
+https://github.com/EbookFoundation/RoE-pipe
-a [Sails v1](https://sailsjs.com) application
-
-
-### Links
-
-+ [Get started](https://sailsjs.com/get-started)
-+ [Sails framework documentation](https://sailsjs.com/documentation)
-+ [Version notes / upgrading](https://sailsjs.com/documentation/upgrading)
-+ [Deployment tips](https://sailsjs.com/documentation/concepts/deployment)
-+ [Community support options](https://sailsjs.com/support)
-+ [Professional / enterprise options](https://sailsjs.com/enterprise)
+## About
+The River of Ebooks serves as an easy-to-use ebook aggregator. Publishers can send metadata from new and updated ebooks through the River where it will be available for any downstream consumers to read, allowing for a more widely available ebook collection. This way, ebooks can be made available on all end user sites, instead of only the site they were published with.
+-----
### Version info
-
This app was originally generated on Tue Oct 16 2018 01:21:31 GMT+0000 (UTC) using Sails v1.0.2.
-
-
-
-
-
-[![Build Status](https://travis-ci.org/miacona96/RoE-pipe.svg?branch=master)](https://travis-ci.org/miacona96/RoE-pipe)
-
-
### Setup
+a [Sails v1](https://sailsjs.com) application
+[![Build Status](https://travis-ci.org/miacona96/RoE-pipe.svg?branch=master)](https://travis-ci.org/miacona96/RoE-pipe)
#### Standalone
diff --git a/api/controllers/HomeController.js b/api/controllers/HomeController.js
new file mode 100644
index 0000000..65eb65a
--- /dev/null
+++ b/api/controllers/HomeController.js
@@ -0,0 +1,21 @@
+module.exports = {
+ show: async function (req, res) {
+ const docsHelper = await sails.helpers.docs()
+ const content = await docsHelper.read('README', '../../')
+ res.view('pages/index', {
+ content
+ })
+ },
+ docs: async function (req, res) {
+ const docsHelper = await sails.helpers.docs()
+ const page = req.param('page')
+ if (!page || !(['api', 'integrations', 'webhooks'].includes(page))) {
+ return res.notFound()
+ }
+ const content = await docsHelper.read(page)
+ res.view('pages/index', {
+ active: page,
+ content
+ })
+ }
+}
diff --git a/api/helpers/docs.js b/api/helpers/docs.js
new file mode 100644
index 0000000..86ccc5f
--- /dev/null
+++ b/api/helpers/docs.js
@@ -0,0 +1,35 @@
+const showdown = require('showdown')
+const fs = require('fs')
+const path = require('path')
+
+showdown.setFlavor('github')
+const converter = new showdown.Converter()
+
+module.exports = {
+ friendlyName: 'Load DocsHelper',
+ description: 'Load a DocsHelper instance',
+ inputs: {},
+ exits: {
+ success: {
+ outputFriendlyName: 'Docs helper',
+ outputDescription: 'A DocsHelper instance'
+ }
+ },
+ fn: async function (inputs, exits) {
+ return exits.success(new DocsHelper())
+ }
+}
+
+class DocsHelper {
+ read (file, relPath = '../../docs') {
+ return new Promise((resolve, reject) => {
+ fs.readFile(path.join(__dirname, relPath, `${file}.md`), { encoding: 'utf8' }, (err, data) => {
+ if (err) reject(err)
+ resolve(converter.makeHtml(data))
+ })
+ })
+ }
+ convert (md) {
+ return converter.makeHtml(md)
+ }
+}
diff --git a/assets/styles/index.scss b/assets/styles/index.scss
index 7f13cdd..e3e9d1b 100644
--- a/assets/styles/index.scss
+++ b/assets/styles/index.scss
@@ -80,3 +80,106 @@
}
}
}
+
+.home {
+ header {
+ height: 50px;
+ line-height: 50px;
+
+ .logo {
+ color: $black-1;
+ text-decoration: none;
+ font-size: 1.2em;
+ padding: 0 20px;
+ }
+ nav {
+ a {
+ text-decoration: none;
+ display: inline-block;
+ line-height: 50px;
+ padding: 0 20px;
+ color: $accent-2;
+
+ &:hover {
+ text-decoration: underline;
+ }
+ &:last-of-type {
+ line-height: 40px;
+ height: 40px;
+ margin: 5px 20px 5px 0;
+ background: $accent-1;
+ color: $text-light-1;
+ border-radius: 3px;
+ }
+ }
+ }
+ }
+ footer {
+ height: 40px;
+ line-height: 40px;
+ background: $accent-1;
+ color: white;
+ padding: 0 20px;
+ box-shadow: $shadow-3;
+
+ a {
+ color: $accent-3;
+ text-decoration: none;
+
+ &:hover {
+ text-decoration: underline;
+ }
+ }
+ }
+ main {
+ background: white;
+ width: 85%;
+ max-width: 900px;
+ box-shadow: $shadow-1;
+ padding: 100px 60px 140px 60px;
+ margin: 60px auto 100px auto;
+
+ h2,
+ h3,
+ h4 {
+ margin: 40px 0 10px 0;
+ font-weight: normal;
+ color: $black-1;
+ }
+ hr {
+ border: none;
+ border-top: 1px solid $black-3;
+ margin: 40px 80px;
+ }
+ a {
+ color: $accent-2;
+ }
+ pre {
+ background: $black-5;
+ padding: 10px;
+ border-radius: 3px;
+
+ &:before {
+ display: block;
+ content: '';
+ background: $accent-3;
+ height: 100%;
+ width: 2px;
+ top: 0;
+ left: 0;
+ }
+ code {
+ background: transparent;
+ padding: 0;
+ }
+ }
+ code {
+ background: $black-5;
+ padding: 2px 5px;
+ border-radius: 3px;
+ }
+ p {
+ line-height: 1.4em;
+ }
+ }
+}
diff --git a/assets/templates/admin.html b/assets/templates/admin.html
index be6453b..6d35f83 100644
--- a/assets/templates/admin.html
+++ b/assets/templates/admin.html
@@ -1,7 +1,7 @@
<% var key, item %>
<% htmlWebpackPlugin.options.links = htmlWebpackPlugin.options.links || [] %>
-
+
River of Ebooks | admin
@@ -10,7 +10,7 @@
if (typeof item === 'string' || item instanceof String) { item = { href: item, rel: 'stylesheet' } } %>
<%= key %>="<%= item[key] %>"<% } %> /><%
} %>
-
+
diff --git a/assets/templates/index.html b/assets/templates/index.html
index 7dae7b5..37e5d18 100644
--- a/assets/templates/index.html
+++ b/assets/templates/index.html
@@ -1,7 +1,7 @@
<% var key, item %>
<% htmlWebpackPlugin.options.links = htmlWebpackPlugin.options.links || [] %>
-
+
River of Ebooks
@@ -10,7 +10,7 @@
if (typeof item === 'string' || item instanceof String) { item = { href: item, rel: 'stylesheet' } } %>
<%= key %>="<%= item[key] %>"<% } %> /><%
} %>
-
+
diff --git a/assets/templates/login.html b/assets/templates/login.html
index a17ff3f..6348d96 100644
--- a/assets/templates/login.html
+++ b/assets/templates/login.html
@@ -1,7 +1,7 @@
<% var key, item %>
<% htmlWebpackPlugin.options.links = htmlWebpackPlugin.options.links || [] %>
-
+
River of Ebooks - Login
@@ -10,7 +10,7 @@
if (typeof item === 'string' || item instanceof String) { item = { href: item, rel: 'stylesheet' } } %>
<%= key %>="<%= item[key] %>"<% } %> /><%
} %>
-
+
diff --git a/config/routes.js b/config/routes.js
index a883f45..a713174 100644
--- a/config/routes.js
+++ b/config/routes.js
@@ -22,9 +22,9 @@ module.exports.routes = {
* *
***************************************************************************/
- 'GET /': {
- view: 'pages/index'
- },
+ 'GET /': 'HomeController.show',
+ 'GET /docs/:page': 'HomeController.docs',
+
'GET /login': {
view: 'pages/login'
},
diff --git a/docs/api.md b/docs/api.md
index 8b9ea69..99a37a5 100644
--- a/docs/api.md
+++ b/docs/api.md
@@ -23,7 +23,7 @@ and body:
Each tuple of `(title, author, version, isbn)` must be unique.
-The `opds` parameter is an opds2 file sent along with the post body.
+The `opds` parameter is an opds2 file containing an opds Publication sent along with the post body.
The server will respond with either:
diff --git a/docs/integrations.md b/docs/integrations.md
new file mode 100644
index 0000000..7b1f4e1
--- /dev/null
+++ b/docs/integrations.md
@@ -0,0 +1,13 @@
+# River of Ebooks Integrations
+## Information on existing RoE integrations with other websites and services
+
+
+### - readthedocs.org
+[view on github](https://github.com/ghowardsit/readthedocs.org)
+New ebooks published using ReadTheDocs will automatically be sent to the River of Ebooks.
+
+
+## Information on building your own integration
+
+To publish ebook metadata through the River of Ebooks, you will first need to register an account and then create a publisher.
+Verifying your ownership of the publisher's domain will increase the chance that your publisher is whitelisted. Once whitelisted, you will be able to use your publisher's appid (key) and secret to POST metadata through the River. You can view the [API documentation here](docs/api). Publishing books is easy - and once published, each new ebook will be available for downstream consumers to find.
diff --git a/docs/webhooks.md b/docs/webhooks.md
index 58dadd8..e3bc627 100644
--- a/docs/webhooks.md
+++ b/docs/webhooks.md
@@ -1,4 +1,9 @@
-# River of Ebooks signed requests
+# River of Ebooks webhooks and signed requests
+## Information on how to receive new publications from RoE
+
+To have RoE send your service any newly published or updated ebooks, you will first need to register an account and then create a Push URI. RoE will send a POST request containing the OPDS2 metadata from any published or updated book to each valid URL. The POST body structure can be viewed in the [API documentation](docs/api).
+
+
## Information on how to verify that requests are sent by RoE
1. Grab your Signing Secret from the bottom of the 'My account' page. In this example, the Signing Secret is `919ac0b6c07b50`. Additionally, extract the raw request body from the request.
diff --git a/package.json b/package.json
index a196121..8e33ae8 100644
--- a/package.json
+++ b/package.json
@@ -52,6 +52,7 @@
"sails-hook-orm": "^2.1.1",
"sails-hook-sockets": "^1.4.0",
"sails-postgresql": "^1.0.2",
+ "showdown": "^1.9.0",
"ta-json-x": "^2.5.0",
"xmldom": "^0.1.27"
},
diff --git a/shrinkwrap.yaml b/shrinkwrap.yaml
index 7c106f8..39ec810 100644
--- a/shrinkwrap.yaml
+++ b/shrinkwrap.yaml
@@ -3,6 +3,7 @@ dependencies:
r2-utils-js: 1.0.6
request: 2.88.0
sails-postgresql: 1.0.2
+ showdown: 1.9.0
ta-json-x: 2.5.0
xmldom: 0.1.27
devDependencies:
@@ -35,6 +36,12 @@ packages:
node: '>=0.10.0'
resolution:
integrity: sha1-w7M6te42DYbg5ijwRorn7yfWVN8=
+ /ansi-regex/3.0.0:
+ dev: false
+ engines:
+ node: '>=4'
+ resolution:
+ integrity: sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=
/ansi-styles/2.2.1:
dev: false
engines:
@@ -176,6 +183,12 @@ packages:
node: '>=0.2.0'
resolution:
integrity: sha1-skV5w77U1tOWru5tmorn9Ugqt7s=
+ /camelcase/4.1.0:
+ dev: false
+ engines:
+ node: '>=4'
+ resolution:
+ integrity: sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=
/caseless/0.12.0:
dev: false
resolution:
@@ -198,6 +211,20 @@ packages:
node: '>=0.10.0'
resolution:
integrity: sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=
+ /cliui/4.1.0:
+ dependencies:
+ string-width: 2.1.1
+ strip-ansi: 4.0.0
+ wrap-ansi: 2.1.0
+ dev: false
+ resolution:
+ integrity: sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==
+ /code-point-at/1.1.0:
+ dev: false
+ engines:
+ node: '>=0.10.0'
+ resolution:
+ integrity: sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=
/combined-stream/1.0.7:
dependencies:
delayed-stream: 1.0.0
@@ -222,6 +249,14 @@ packages:
dev: false
resolution:
integrity: sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=
+ /cross-spawn/5.1.0:
+ dependencies:
+ lru-cache: 4.1.5
+ shebang-command: 1.2.0
+ which: 1.3.1
+ dev: false
+ resolution:
+ integrity: sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=
/dashdash/1.14.1:
dependencies:
assert-plus: 1.0.0
@@ -248,6 +283,12 @@ packages:
dev: false
resolution:
integrity: sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==
+ /decamelize/1.2.0:
+ dev: false
+ engines:
+ node: '>=0.10.0'
+ resolution:
+ integrity: sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=
/delayed-stream/1.0.0:
dev: false
engines:
@@ -285,6 +326,20 @@ packages:
node: '>=0.8.0'
resolution:
integrity: sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=
+ /execa/0.7.0:
+ dependencies:
+ cross-spawn: 5.1.0
+ get-stream: 3.0.0
+ is-stream: 1.1.0
+ npm-run-path: 2.0.2
+ p-finally: 1.0.0
+ signal-exit: 3.0.2
+ strip-eof: 1.0.0
+ dev: false
+ engines:
+ node: '>=4'
+ resolution:
+ integrity: sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=
/expand-brackets/0.1.5:
dependencies:
is-posix-bracket: 0.1.1
@@ -392,6 +447,14 @@ packages:
node: '>=0.10.0'
resolution:
integrity: sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q==
+ /find-up/2.1.0:
+ dependencies:
+ locate-path: 2.0.0
+ dev: false
+ engines:
+ node: '>=4'
+ resolution:
+ integrity: sha1-RdG35QbHF93UgndaK3eSCjwMV6c=
/findup-sync/0.4.3:
dependencies:
detect-file: 0.1.0
@@ -486,6 +549,16 @@ packages:
node: '>= 0.8.0'
resolution:
integrity: sha1-OMYYhRPhQDCUjsblz2VSPZd5KZs=
+ /get-caller-file/1.0.3:
+ dev: false
+ resolution:
+ integrity: sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==
+ /get-stream/3.0.0:
+ dev: false
+ engines:
+ node: '>=4'
+ resolution:
+ integrity: sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=
/getpass/0.1.7:
dependencies:
assert-plus: 1.0.0
@@ -630,6 +703,12 @@ packages:
dev: true
resolution:
integrity: sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==
+ /invert-kv/1.0.0:
+ dev: false
+ engines:
+ node: '>=0.10.0'
+ resolution:
+ integrity: sha1-EEqOSqym09jNFXqO+L+rLXo//bY=
/is-buffer/1.1.6:
dev: false
resolution:
@@ -660,6 +739,20 @@ packages:
node: '>=0.10.0'
resolution:
integrity: sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=
+ /is-fullwidth-code-point/1.0.0:
+ dependencies:
+ number-is-nan: 1.0.1
+ dev: false
+ engines:
+ node: '>=0.10.0'
+ resolution:
+ integrity: sha1-754xOG8DGn8NZDr4L95QxFfvAMs=
+ /is-fullwidth-code-point/2.0.0:
+ dev: false
+ engines:
+ node: '>=4'
+ resolution:
+ integrity: sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=
/is-glob/2.0.1:
dependencies:
is-extglob: 1.0.0
@@ -694,6 +787,12 @@ packages:
node: '>=0.10.0'
resolution:
integrity: sha1-IHurkWOEmcB7Kt8kCkGochADRXU=
+ /is-stream/1.1.0:
+ dev: false
+ engines:
+ node: '>=0.10.0'
+ resolution:
+ integrity: sha1-EtSj3U5o4Lec6428hBc66A2RykQ=
/is-typedarray/1.0.0:
dev: false
resolution:
@@ -814,6 +913,14 @@ packages:
hasBin: true
resolution:
integrity: sha1-V5P1efB6KTi/mHRpPXS7pVxbqhw=
+ /lcid/1.0.0:
+ dependencies:
+ invert-kv: 1.0.0
+ dev: false
+ engines:
+ node: '>=0.10.0'
+ resolution:
+ integrity: sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=
/liftoff/2.2.5:
dependencies:
extend: 3.0.2
@@ -830,6 +937,15 @@ packages:
dev: false
resolution:
integrity: sha1-hMinKrWcRyUyFIDJdeZQg0LnCTc=
+ /locate-path/2.0.0:
+ dependencies:
+ p-locate: 2.0.0
+ path-exists: 3.0.0
+ dev: false
+ engines:
+ node: '>=4'
+ resolution:
+ integrity: sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=
/lodash/4.17.11:
dev: false
resolution:
@@ -841,6 +957,13 @@ packages:
hasBin: true
resolution:
integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
+ /lru-cache/4.1.5:
+ dependencies:
+ pseudomap: 1.0.2
+ yallist: 2.1.2
+ dev: false
+ resolution:
+ integrity: sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==
/machine/15.2.2:
dependencies:
'@sailshq/lodash': 3.10.3
@@ -867,6 +990,14 @@ packages:
dev: false
resolution:
integrity: sha512-rUxjysqif/BZQH2yhd5Aaq7vXMSx9NdEsQcyA07uEzIvxgI7zIr33gGsh+RU0/XjmQpCW7RsVof1vlkvQVCK5A==
+ /mem/1.1.0:
+ dependencies:
+ mimic-fn: 1.2.0
+ dev: false
+ engines:
+ node: '>=4'
+ resolution:
+ integrity: sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y=
/micromatch/2.3.11:
dependencies:
arr-diff: 2.0.0
@@ -901,6 +1032,12 @@ packages:
node: '>= 0.6'
resolution:
integrity: sha512-aGl6TZGnhm/li6F7yx82bJiBZwgiEa4Hf6CNr8YO+r5UHr53tSTYZb102zyU50DOWWKeOv0uQLRL0/9EiKWCog==
+ /mimic-fn/1.2.0:
+ dev: false
+ engines:
+ node: '>=4'
+ resolution:
+ integrity: sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==
/minimatch/3.0.4:
dependencies:
brace-expansion: 1.1.11
@@ -952,6 +1089,20 @@ packages:
node: '>=0.10.0'
resolution:
integrity: sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=
+ /npm-run-path/2.0.2:
+ dependencies:
+ path-key: 2.0.1
+ dev: false
+ engines:
+ node: '>=4'
+ resolution:
+ integrity: sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=
+ /number-is-nan/1.0.1:
+ dev: false
+ engines:
+ node: '>=0.10.0'
+ resolution:
+ integrity: sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=
/oauth-sign/0.9.0:
dev: false
resolution:
@@ -989,6 +1140,44 @@ packages:
node: '>=0.10.0'
resolution:
integrity: sha1-/7xJiDNuDoM94MFox+8VISGqf7M=
+ /os-locale/2.1.0:
+ dependencies:
+ execa: 0.7.0
+ lcid: 1.0.0
+ mem: 1.1.0
+ dev: false
+ engines:
+ node: '>=4'
+ resolution:
+ integrity: sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA==
+ /p-finally/1.0.0:
+ dev: false
+ engines:
+ node: '>=4'
+ resolution:
+ integrity: sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=
+ /p-limit/1.3.0:
+ dependencies:
+ p-try: 1.0.0
+ dev: false
+ engines:
+ node: '>=4'
+ resolution:
+ integrity: sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==
+ /p-locate/2.0.0:
+ dependencies:
+ p-limit: 1.3.0
+ dev: false
+ engines:
+ node: '>=4'
+ resolution:
+ integrity: sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=
+ /p-try/1.0.0:
+ dev: false
+ engines:
+ node: '>=4'
+ resolution:
+ integrity: sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=
/packet-reader/0.2.0:
dev: false
resolution:
@@ -1018,12 +1207,24 @@ packages:
node: '>=0.10.0'
resolution:
integrity: sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=
+ /path-exists/3.0.0:
+ dev: false
+ engines:
+ node: '>=4'
+ resolution:
+ integrity: sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=
/path-is-absolute/1.0.1:
dev: false
engines:
node: '>=0.10.0'
resolution:
integrity: sha1-F0uSaHNVNP+8es5r9TpanhtcX18=
+ /path-key/2.0.1:
+ dev: false
+ engines:
+ node: '>=4'
+ resolution:
+ integrity: sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=
/path-parse/1.0.6:
dev: false
resolution:
@@ -1142,6 +1343,10 @@ packages:
dev: false
resolution:
integrity: sha1-zv9d2J0+XxD7deHo52vHWAGlnDQ=
+ /pseudomap/1.0.2:
+ dev: false
+ resolution:
+ integrity: sha1-8FKijacOYYkX7wqKw0wa5aaChrM=
/psl/1.1.31:
dev: false
resolution:
@@ -1394,6 +1599,16 @@ packages:
node: '>= 4'
resolution:
integrity: sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==
+ /require-directory/2.1.1:
+ dev: false
+ engines:
+ node: '>=0.10.0'
+ resolution:
+ integrity: sha1-jGStX9MNqxyXbiNE/+f3kqam30I=
+ /require-main-filename/1.0.1:
+ dev: false
+ resolution:
+ integrity: sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=
/resolve-dir/0.1.1:
dependencies:
expand-tilde: 1.2.2
@@ -1457,10 +1672,39 @@ packages:
hasBin: true
resolution:
integrity: sha1-x6BxWKgL7dBSNVt3DYLWZA+AO+c=
+ /set-blocking/2.0.0:
+ dev: false
+ resolution:
+ integrity: sha1-BF+XgtARrppoA93TgrJDkrPYkPc=
/setimmediate/1.0.5:
dev: false
resolution:
integrity: sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=
+ /shebang-command/1.2.0:
+ dependencies:
+ shebang-regex: 1.0.0
+ dev: false
+ engines:
+ node: '>=0.10.0'
+ resolution:
+ integrity: sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=
+ /shebang-regex/1.0.0:
+ dev: false
+ engines:
+ node: '>=0.10.0'
+ resolution:
+ integrity: sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=
+ /showdown/1.9.0:
+ dependencies:
+ yargs: 10.1.2
+ dev: false
+ hasBin: true
+ resolution:
+ integrity: sha512-x7xDCRIaOlicbC57nMhGfKamu+ghwsdVkHMttyn+DelwzuHOx4OHCVL/UW/2QOLH7BxfCcCCVVUix3boKXJKXQ==
+ /signal-exit/3.0.2:
+ dev: false
+ resolution:
+ integrity: sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=
/slugify/1.3.4:
dev: false
engines:
@@ -1496,6 +1740,25 @@ packages:
node: '>=0.10.0'
resolution:
integrity: sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=
+ /string-width/1.0.2:
+ dependencies:
+ code-point-at: 1.1.0
+ is-fullwidth-code-point: 1.0.0
+ strip-ansi: 3.0.1
+ dev: false
+ engines:
+ node: '>=0.10.0'
+ resolution:
+ integrity: sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=
+ /string-width/2.1.1:
+ dependencies:
+ is-fullwidth-code-point: 2.0.0
+ strip-ansi: 4.0.0
+ dev: false
+ engines:
+ node: '>=4'
+ resolution:
+ integrity: sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==
/string_decoder/0.10.31:
dev: false
resolution:
@@ -1514,6 +1777,20 @@ packages:
node: '>=0.10.0'
resolution:
integrity: sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=
+ /strip-ansi/4.0.0:
+ dependencies:
+ ansi-regex: 3.0.0
+ dev: false
+ engines:
+ node: '>=4'
+ resolution:
+ integrity: sha1-qEeQIusaw2iocTibY1JixQXuNo8=
+ /strip-eof/1.0.0:
+ dev: false
+ engines:
+ node: '>=0.10.0'
+ resolution:
+ integrity: sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=
/supports-color/2.0.0:
dev: false
engines:
@@ -1678,6 +1955,10 @@ packages:
dev: false
resolution:
integrity: sha512-WsS1yRw8xT6O7iIK8oAcYr3/vhMYiTHdA/vQnU/JsGbcad2Xi4p8bie8/F+BoEyN7SEpBZ8nFT9OdszDAt7Ugg==
+ /which-module/2.0.0:
+ dev: false
+ resolution:
+ integrity: sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=
/which/1.3.1:
dependencies:
isexe: 2.0.0
@@ -1685,6 +1966,15 @@ packages:
hasBin: true
resolution:
integrity: sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==
+ /wrap-ansi/2.1.0:
+ dependencies:
+ string-width: 1.0.2
+ strip-ansi: 3.0.1
+ dev: false
+ engines:
+ node: '>=0.10.0'
+ resolution:
+ integrity: sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=
/wrappy/1.0.2:
dev: false
resolution:
@@ -1707,6 +1997,37 @@ packages:
node: '>=0.4'
resolution:
integrity: sha1-pcbVMr5lbiPbgg77lDofBJmNY68=
+ /y18n/3.2.1:
+ dev: false
+ resolution:
+ integrity: sha1-bRX7qITAhnnA136I53WegR4H+kE=
+ /yallist/2.1.2:
+ dev: false
+ resolution:
+ integrity: sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=
+ /yargs-parser/8.1.0:
+ dependencies:
+ camelcase: 4.1.0
+ dev: false
+ resolution:
+ integrity: sha512-yP+6QqN8BmrgW2ggLtTbdrOyBNSI7zBa4IykmiV5R1wl1JWNxQvWhMfMdmzIYtKU7oP3OOInY/tl2ov3BDjnJQ==
+ /yargs/10.1.2:
+ dependencies:
+ cliui: 4.1.0
+ decamelize: 1.2.0
+ find-up: 2.1.0
+ get-caller-file: 1.0.3
+ os-locale: 2.1.0
+ require-directory: 2.1.1
+ require-main-filename: 1.0.1
+ set-blocking: 2.0.0
+ string-width: 2.1.1
+ which-module: 2.0.0
+ y18n: 3.2.1
+ yargs-parser: 8.1.0
+ dev: false
+ resolution:
+ integrity: sha512-ivSoxqBGYOqQVruxD35+EyCFDYNEFL/Uo6FcOnz+9xZdZzK0Zzw4r4KhbrME1Oo2gOggwJod2MnsdamSG7H9ig==
/yauzl/2.10.0:
dependencies:
buffer-crc32: 0.2.13
@@ -1730,5 +2051,6 @@ specifiers:
react-router-dom: ^4.3.1
request: ^2.88.0
sails-postgresql: ^1.0.2
+ showdown: ^1.9.0
ta-json-x: ^2.5.0
xmldom: ^0.1.27
diff --git a/views/pages/index.ejs b/views/pages/index.ejs
index 107b499..6aad79f 100644
--- a/views/pages/index.ejs
+++ b/views/pages/index.ejs
@@ -1,79 +1,19 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
Get your bearings
-
- If you're new to Sails, get started here .
-
- (You'll learn about the framework and explore the files that were generated in this new app.)
-
-
-
-
-
-
-
Lift your app
-
- Looks like you already ran sails lift
to start up your app server. Nice work!
-
- (Remember to re-lift after making backend code changes.)
-
-
-
-
-
-
-
Dive in
-
- Blueprints are just the beginning. You'll probably also want to learn how to customize your app's routes , build custom actions , set up security policies , configure your data sources , and deploy to production .
-
- (For more help getting started, check out the links on this page.)
-
-
-
-
-
-
-
+
+
+
+
+ River of Ebooks
+
+
+
+
+
+ <%- partial('../shared/header.html') %>
+
+ <% if (content) { %>
+ <%- content %>
+ <% } %>
+
+ <%- partial('../shared/footer.html') %>
+
+
diff --git a/views/shared/footer.html b/views/shared/footer.html
new file mode 100644
index 0000000..732866d
--- /dev/null
+++ b/views/shared/footer.html
@@ -0,0 +1,3 @@
+
diff --git a/views/shared/header.html b/views/shared/header.html
new file mode 100644
index 0000000..8c6ef3f
--- /dev/null
+++ b/views/shared/header.html
@@ -0,0 +1,10 @@
+