From 7a04d1a91660a3376190c488a485f77d1b5f497d Mon Sep 17 00:00:00 2001 From: "Glitch (glitch-fediverse-bot)" Date: Tue, 9 Oct 2018 12:50:42 +0000 Subject: [PATCH] Minor design improvements. Work in progress on bot replies. --- .gitignore | 2 + .glitch-assets | 5 + README.md | 2 +- bot/README.md | 6 + bot.js => bot/bot.js | 84 ++++++-- bot/responses.js | 43 +++++ examples/replies/README.md | 15 ++ examples/replies/bot/bot-replies.js | 43 +++++ helpers/db.js | 95 +++++++-- package.json | 3 +- routes/admin.js | 2 +- routes/bot-endpoint.js | 2 +- routes/bot.js | 2 +- routes/delete-post.js | 2 +- routes/inbox.js | 58 +++++- routes/index.js | 9 +- routes/outbox.js | 2 +- routes/pubsub.js | 2 +- routes/salmon.js | 2 +- routes/webhook.js | 2 +- routes/well-known.js | 2 +- server.js | 13 +- sessions | Bin 147456 -> 0 bytes shrinkwrap.yaml | 287 ++++++++++++++++++++++++++++ src/styles/_layout.scss | 44 ++++- views/home.handlebars | 11 +- views/post.handlebars | 6 +- 27 files changed, 680 insertions(+), 64 deletions(-) create mode 100644 .gitignore create mode 100644 bot/README.md rename bot.js => bot/bot.js (74%) create mode 100644 bot/responses.js create mode 100644 examples/replies/README.md create mode 100644 examples/replies/bot/bot-replies.js delete mode 100644 sessions diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..09b0fe8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +node_modules +sessions diff --git a/.glitch-assets b/.glitch-assets index 21daff0..7bde543 100644 --- a/.glitch-assets +++ b/.glitch-assets @@ -13,3 +13,8 @@ {"name":"glitch-fediverse-bot.png","date":"2018-09-29T12:49:07.963Z","url":"https://cdn.glitch.com/a4825d5c-d1d6-4780-8464-8636780177ef%2Fglitch-fediverse-bot.png","type":"image/png","size":58653,"imageWidth":1920,"imageHeight":1079,"thumbnail":"https://cdn.glitch.com/a4825d5c-d1d6-4780-8464-8636780177ef%2Fthumbnails%2Fglitch-fediverse-bot.png","thumbnailWidth":330,"thumbnailHeight":186,"dominantColor":"rgb(252,252,252)","uuid":"0KNy0WXAgI1pZ0fd"} {"name":"glitch-fediverse-bot-960px.png","date":"2018-09-29T12:49:08.030Z","url":"https://cdn.glitch.com/a4825d5c-d1d6-4780-8464-8636780177ef%2Fglitch-fediverse-bot-960px.png","type":"image/png","size":50867,"imageWidth":960,"imageHeight":540,"thumbnail":"https://cdn.glitch.com/a4825d5c-d1d6-4780-8464-8636780177ef%2Fthumbnails%2Fglitch-fediverse-bot-960px.png","thumbnailWidth":330,"thumbnailHeight":186,"dominantColor":"rgb(252,252,252)","uuid":"8tHyMsnvvVKkjFXF"} {"name":"glitch-fediverse-bot-with-image.png","date":"2018-10-03T21:11:53.744Z","url":"https://cdn.glitch.com/a4825d5c-d1d6-4780-8464-8636780177ef%2Fglitch-fediverse-bot-with-image.png","type":"image/png","size":469823,"imageWidth":2880,"imageHeight":1465,"thumbnail":"https://cdn.glitch.com/a4825d5c-d1d6-4780-8464-8636780177ef%2Fthumbnails%2Fglitch-fediverse-bot-with-image.png","thumbnailWidth":330,"thumbnailHeight":168,"dominantColor":"rgb(252,252,252)","uuid":"oHDFFpP6XyCauPmh"} +{"name":"bot-replies.png","date":"2018-10-09T12:35:59.939Z","url":"https://cdn.glitch.com/a4825d5c-d1d6-4780-8464-8636780177ef%2Fbot-replies.png","type":"image/png","size":186912,"imageWidth":2834,"imageHeight":1256,"thumbnail":"https://cdn.glitch.com/a4825d5c-d1d6-4780-8464-8636780177ef%2Fthumbnails%2Fbot-replies.png","thumbnailWidth":330,"thumbnailHeight":147,"dominantColor":"rgb(236,244,244)","uuid":"sHZ0AbdbgCtnaQYM"} +{"uuid":"iLCHg6pDTsAX7jkg","deleted":true} +{"uuid":"0KNy0WXAgI1pZ0fd","deleted":true} +{"uuid":"8tHyMsnvvVKkjFXF","deleted":true} +{"name":"glitch-fediverse-bot.png","date":"2018-10-09T12:49:00.686Z","url":"https://cdn.glitch.com/a4825d5c-d1d6-4780-8464-8636780177ef%2Fglitch-fediverse-bot.png","type":"image/png","size":206001,"imageWidth":2854,"imageHeight":1398,"thumbnail":"https://cdn.glitch.com/a4825d5c-d1d6-4780-8464-8636780177ef%2Fthumbnails%2Fglitch-fediverse-bot.png","thumbnailWidth":330,"thumbnailHeight":162,"dominantColor":"rgb(236,244,244)","uuid":"6oFnGGQy88GLx9Be"} diff --git a/README.md b/README.md index b273546..a097ce6 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ **Note**: This project is under active development and not available for remixing, but you can [import it from GitHub](https://glitch.com/#!/import/github/fourtonfish/glitch-fediverse-bot). -![Glitch Fediverse bot](https://cdn.glitch.com/a4825d5c-d1d6-4780-8464-8636780177ef%2Fglitch-fediverse-bot-small-1024px.png?1538225347895) +![Glitch Fediverse bot](https://cdn.glitch.com/a4825d5c-d1d6-4780-8464-8636780177ef%2Fglitch-fediverse-bot.png) # Glitch Fediverse bot diff --git a/bot/README.md b/bot/README.md new file mode 100644 index 0000000..46ad3b0 --- /dev/null +++ b/bot/README.md @@ -0,0 +1,6 @@ +# Bot logic + +The files in the `/bot` folder contain the source code for the bot's behavior. + +- Inside `bot.js` you'll find internal methods, like `create_post` and `delete_post`. +- To change bot's responses to messages it receives, see `responses.js`. diff --git a/bot.js b/bot/bot.js similarity index 74% rename from bot.js rename to bot/bot.js index 44fede3..1f3ed37 100644 --- a/bot.js +++ b/bot/bot.js @@ -3,12 +3,13 @@ var fs = require('fs'), url = require('url'), util = require('util'), moment = require('moment'), - db = require(__dirname + '/helpers/db.js'), - keys = require(__dirname + '/helpers/keys.js'), + db = require(__dirname + '/../helpers/db.js'), + keys = require(__dirname + '/../helpers/keys.js'), request = require('request'), public_key_path = '.data/rsa/pubKey', private_key_path = '.data/rsa/privKey', - bot_url = `https://${process.env.PROJECT_DOMAIN}.glitch.me`; + bot_url = `https://${process.env.PROJECT_DOMAIN}.glitch.me`, + bot_compose_reply = require(__dirname + '/responses.js'); if (!fs.existsSync(public_key_path) || !fs.existsSync(private_key_path)) { keys.generate_keys(function(){ @@ -21,7 +22,7 @@ else{ module.exports = { bot_url: bot_url, - links: [ + links: [ // { // rel: 'http://webfinger.net/rel/profile-page', // type: 'text/html', @@ -74,6 +75,28 @@ else{ 'publicKeyPem': public_key } }, + compose_reply: bot_compose_reply, + send_reply: function(options, cb){ + var bot = this, + reply_to_username = ''; + + try{ + var actor_url_parts = options.payload.actor.split('/'); + var username = actor_url_parts[actor_url_parts.length-1]; + reply_to_username = `@${username}@${url.parse(options.payload.actor).hostname} `; + + console.log({reply_to_username}); + } catch(err){ /*noop*/ } + + bot.create_post({ + type: 'Note', + content: `
${options.payload.object.content}

${options.payload.object.url}

${options.reply_message}

`, + reply_message: `${reply_to_username} ${options.reply_message}`, + in_reply_to: options.payload.object.url + }, function(err, message){ + // console.log(err, message); + }); + }, create_post: function(options, cb){ var bot = this; @@ -86,6 +109,7 @@ else{ post_description = options.description, post_date = moment().format(), post_in_reply_to = options.in_reply_to || null, + reply_message = options.reply_message || null, post_content = options.content || options.url || '', post_attachment = JSON.stringify(options.attachment) || '[]'; @@ -104,7 +128,7 @@ else{ 'type': post_type, 'published': post_date, 'attributedTo': `${bot_url}/bot`, - 'content': post_content, + 'content': reply_message || post_content, 'to': 'https://www.w3.org/ns/activitystreams#Public' }; @@ -122,18 +146,20 @@ else{ } } + if (post_in_reply_to){ + post_object.inReplyTo = post_in_reply_to; + } + var post = { '@context': 'https://www.w3.org/ns/activitystreams', 'id': `${bot_url}/post/${post_id}`, 'type': 'Create', 'actor': `${bot_url}/bot`, 'object': post_object - } - - if (options.post_in_reply_to){ - post.object.inReplyTo = post_in_reply_to; } - + + console.log({post_in_reply_to}); + db.get_followers(function(err, followers){ if (followers){ console.log(`sending update to ${followers.length} follower(s)...`); @@ -179,8 +205,12 @@ else{ }); }, accept: function(payload, cb){ - var bot = this, - guid = crypto.randomBytes(16).toString('hex'); + var bot = this, + guid = crypto.randomBytes(16).toString('hex'); + + db.get_event(payload.id, function(err, data){ + // console.log('get_event', err, data); + bot.sign_and_send({ follower: { @@ -197,7 +227,37 @@ else{ if (cb){ cb(err, payload, data); } + console.log('saving event', payload.id) + db.save_event(payload.id); }); + + }); +// db.get_event(payload.id, function(err, data){ +// console.log('get_event', err, data); + +// if (!err && !data){ +// bot.sign_and_send({ +// follower: { +// url: payload.actor +// }, +// message: { +// '@context': 'https://www.w3.org/ns/activitystreams', +// 'id': `${bot.bot_url}/${guid}`, +// 'type': 'Accept', +// 'actor': `${bot.bot_url}/bot`, +// 'object': payload, +// } +// }, function(err, data){ +// if (cb){ +// cb(err, payload, data); +// } +// console.log('saving event', payload.id) +// db.save_event(payload.id); +// }); +// } else if (!err){ +// console.log('duplicate event'); +// } +// }); }, sign_and_send: function(options, cb){ var bot = this; diff --git a/bot/responses.js b/bot/responses.js new file mode 100644 index 0000000..24b2d8b --- /dev/null +++ b/bot/responses.js @@ -0,0 +1,43 @@ +/* + Here you can modify how the bot responds to messages it receives. +*/ + +module.exports = function(data, callback_function) { +/* + At the end of this function we need to pass an error message and a response text. + Let's set up some default values. +*/ + + var error = null, + response = 'Hello 👋'; + +/* + The data object this function receives looks like this: + + data = { + payload: 'The original data object.', + message_body: 'The content of the message sent to the bot.', + message_from: 'The URL of the message sender.' + } + + message_body and message_from come from the payload object, so we can access them more conveniently. If we need more details, we can get those from the payload object itself. + +*/ + + console.log(`new message from ${data.message_from}:`) + console.log(data.message_body); + +/* + We can modify the response text. +*/ + + if (data.message_body.toLowerCase().indexOf('hello') > -1){ + response = 'Hi 👋'; + } + + /* + Finally, we pass the error and reply message to the callback function that sends it to the author of the message that the bot received and saves it to the post database. + */ + + callback_function(error, response); +}; diff --git a/examples/replies/README.md b/examples/replies/README.md new file mode 100644 index 0000000..78f436c --- /dev/null +++ b/examples/replies/README.md @@ -0,0 +1,15 @@ +**Work in progress** + +![A bot replying to a message](https://cdn.glitch.com/a4825d5c-d1d6-4780-8464-8636780177ef%2Fbot-replies.png?1539088559939) + +# Bot replies + +To use bot replies, update `bot/responses.js` with a function that returns a reply message. + + +TODO: + +- correctly dedupe events +- add support for private messages +- send notification when posting reply + diff --git a/examples/replies/bot/bot-replies.js b/examples/replies/bot/bot-replies.js new file mode 100644 index 0000000..24b2d8b --- /dev/null +++ b/examples/replies/bot/bot-replies.js @@ -0,0 +1,43 @@ +/* + Here you can modify how the bot responds to messages it receives. +*/ + +module.exports = function(data, callback_function) { +/* + At the end of this function we need to pass an error message and a response text. + Let's set up some default values. +*/ + + var error = null, + response = 'Hello 👋'; + +/* + The data object this function receives looks like this: + + data = { + payload: 'The original data object.', + message_body: 'The content of the message sent to the bot.', + message_from: 'The URL of the message sender.' + } + + message_body and message_from come from the payload object, so we can access them more conveniently. If we need more details, we can get those from the payload object itself. + +*/ + + console.log(`new message from ${data.message_from}:`) + console.log(data.message_body); + +/* + We can modify the response text. +*/ + + if (data.message_body.toLowerCase().indexOf('hello') > -1){ + response = 'Hi 👋'; + } + + /* + Finally, we pass the error and reply message to the callback function that sends it to the author of the message that the bot received and saves it to the post database. + */ + + callback_function(error, response); +}; diff --git a/helpers/db.js b/helpers/db.js index 4beecd5..d415360 100644 --- a/helpers/db.js +++ b/helpers/db.js @@ -12,6 +12,7 @@ Posts table id INT NOT NULL AUTO_INCREMENT date DATETIME DEFAULT current_timestamp type VARCHAR(255) +in_reply_to TEXT content TEXT attachment TEXT [this is a stringified JSON, see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-attachment] @@ -20,30 +21,39 @@ Followers table url TEXT PRIMARY KEY date DATETIME DEFAULT current_timestamp +Events table + +id TEXT PRIMARY +date DATETIME DEFAULT current_timestamp + + */ module.exports = { init: function(cb){ db.serialize(function(){ /* - TODO: Rewrite this with promises. + TODO: Rewrite this with promises and callback support. */ - db.run('CREATE TABLE IF NOT EXISTS Posts (id INTEGER PRIMARY KEY AUTOINCREMENT, date DATETIME DEFAULT current_timestamp, type VARCHAR(255), content TEXT, attachment TEXT)', function(err, data){ + + db.run('CREATE TABLE IF NOT EXISTS Posts (id INTEGER PRIMARY KEY AUTOINCREMENT, date DATETIME DEFAULT current_timestamp, type VARCHAR(255), in_reply_to TEXT, content TEXT, attachment TEXT)', function(err, data){ + if (err){ + console.log(err); + } + }); + + db.run('CREATE TABLE IF NOT EXISTS Followers (url TEXT PRIMARY KEY, date DATETIME DEFAULT current_timestamp)', function(err, data){ if (err){ console.log(err); } - else{ - db.run('CREATE TABLE IF NOT EXISTS Followers (url TEXT PRIMARY KEY, date DATETIME DEFAULT current_timestamp)', function(err, data){ - // db.run('CREATE TABLE IF NOT EXISTS Followers (id INTEGER PRIMARY KEY AUTOINCREMENT, date DATETIME DEFAULT current_timestamp, url TEXT)', function(err, data){ - if (err){ - console.log(err); - } - else{ - console.log('DB ready...'); - } - }); + }); + + db.run('CREATE TABLE IF NOT EXISTS Events (id TEXT PRIMARY KEY, date DATETIME DEFAULT current_timestamp)', function(err, data){ + if (err){ + console.log(err); } }); + }); }, get_posts: function(options, cb){ @@ -58,10 +68,13 @@ module.exports = { */ db.all('SELECT COUNT(*) AS total_count FROM Posts', function(err, rows) { - var total_count = rows[0].total_count, - total_pages= Math.ceil(total_count/POSTS_PER_PAGE); - + var total_count = 0; + + if (rows){ + total_count = rows[0].total_count; + } + var total_pages = Math.ceil(total_count/POSTS_PER_PAGE); var db_query = `SELECT * from Posts ORDER BY date DESC LIMIT ${POSTS_PER_PAGE} OFFSET ${offset}`; db.all(db_query, function(err, rows) { @@ -71,7 +84,7 @@ module.exports = { page_count: total_pages, posts: rows }; - cb(null, db_return); + cb(err, db_return); } }); @@ -84,7 +97,7 @@ module.exports = { db.all(`SELECT * from Posts WHERE id=${post_id}`, function(err, rows) { if (cb){ var post_data = (rows ? rows[0] : null); - cb(null, post_data); + cb(err, post_data); } }); }); @@ -92,11 +105,12 @@ module.exports = { save_post: function(post_data, cb){ var post_type = post_data.type || 'Note', post_content = post_data.content || '', + in_reply_to = post_data.in_reply_to || '', post_attachment = post_data.attachment.toString() || '[]'; db.serialize(function() { // db.run(`INSERT INTO Posts (type, content, attachment) VALUES ("${post_type}", "${post_content}", "${post_attachment}")`, function(err, data){ - db.run(`INSERT INTO Posts (type, content, attachment) VALUES ('${post_type}', '${post_content}', '${post_attachment}')`, function(err, data){ + db.run(`INSERT INTO Posts (type, content, in_reply_to, attachment) VALUES ('${post_type}', '${post_content}', '${in_reply_to}', '${post_attachment}')`, function(err, data){ if (err){ console.log(err); } @@ -139,11 +153,54 @@ module.exports = { db.all("SELECT * from Followers ORDER BY date DESC", function(err, rows) { if (cb){ - cb(null, rows); + cb(err, rows); + } + }); + }); + }, + save_event: function(event_id, cb){ + db.serialize(function() { + db.run(`INSERT INTO Events (id) VALUES ('${event_id}')`, function(err, data){ + if (err){ + console.log(err); + } + if (cb){ + cb(err, this); + } + }); + }); + }, + get_event: function(event_id, cb){ + var data = []; + db.serialize(function(){ + db.all(`SELECT * from Events WHERE id='${event_id}'`, function(err, rows) { + if (cb){ + var data = (rows ? rows[0] : null); + cb(err, data); } }); }); }, + get_events: function(cb){ + db.serialize(function(){ + db.all('SELECT * FROM Events', function(err, rows) { + if (cb){ + cb(err, rows); + } + }); + }); + }, + get_replies: function(in_reply_to, cb){ + var data = []; + db.serialize(function(){ + db.all(`SELECT * from Posts WHERE in_reply_to='${in_reply_to}'`, function(err, rows) { + if (cb){ + var post_data = (rows ? rows[0] : null); + cb(err, post_data); + } + }); + }); + }, drop_table: function(table, cb){ db.serialize(function(){ if (table && exists) { diff --git a/package.json b/package.json index 80126be..1028890 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,8 @@ "canvas": "^2.0.0-alpha.17", "color-scheme": "^1.0.1", "gifencoder": "^1.1.0", - "neocities": "^0.0.3" + "neocities": "^0.0.3", + "jsdom": "^12.1.0" }, "engines": { "node": "8.x" diff --git a/routes/admin.js b/routes/admin.js index e573ad2..f061f52 100644 --- a/routes/admin.js +++ b/routes/admin.js @@ -3,7 +3,7 @@ var express = require('express'), router = express.Router(), moment = require('moment'), db = require(__dirname + '/../helpers/db.js'), - bot = require(__dirname + '/../bot.js'); + bot = require(__dirname + '/../bot/bot.js'); diff --git a/routes/bot-endpoint.js b/routes/bot-endpoint.js index bc071aa..41b105a 100644 --- a/routes/bot-endpoint.js +++ b/routes/bot-endpoint.js @@ -1,7 +1,7 @@ var express = require('express'), router = express.Router(), grammar = require(__dirname + '/../tracery/tracery.js').grammar, - bot = require(__dirname + '/../bot.js'); + bot = require(__dirname + '/../bot/bot.js'); router.get('/', function (req, res) { var content = grammar.flatten("#origin#"); diff --git a/routes/bot.js b/routes/bot.js index 6b055f0..d4775b6 100644 --- a/routes/bot.js +++ b/routes/bot.js @@ -1,7 +1,7 @@ var fs = require('fs'), url = require('url'), util = require('util'), - bot = require(__dirname + '/../bot.js'); + bot = require(__dirname + '/../bot/bot.js'); var express = require('express'), diff --git a/routes/delete-post.js b/routes/delete-post.js index 99e3021..851d968 100644 --- a/routes/delete-post.js +++ b/routes/delete-post.js @@ -1,7 +1,7 @@ var express = require('express'), router = express.Router(), moment = require('moment'), - bot = require(__dirname + '/../bot.js'), + bot = require(__dirname + '/../bot/bot.js'), db = require(__dirname + '/../helpers/db.js'); router.get('/:id', function(req, res) { diff --git a/routes/inbox.js b/routes/inbox.js index c58da10..e8ba23b 100644 --- a/routes/inbox.js +++ b/routes/inbox.js @@ -2,9 +2,11 @@ var fs = require('fs'), url = require('url'), crypto = require('crypto'), util = require('util'), + jsdom = require('jsdom'), db = require(__dirname + '/../helpers/db.js'), - bot = require(__dirname + '/../bot.js'); + bot = require(__dirname + '/../bot/bot.js'); +const { JSDOM } = jsdom; var express = require('express'), router = express.Router(); @@ -13,7 +15,10 @@ router.post('/', function (req, res) { var url_parts = url.parse(req.url, true), payload = req.body; - console.log('/inbox'); + console.log('/inbox'); + + console.log(payload.id); + /* TODO: Verify the message. */ @@ -21,19 +26,52 @@ router.post('/', function (req, res) { if (payload.type === 'Follow'){ bot.accept(payload, function(err, payload, data){ - db.save_follower(payload, function(err, data){ - console.log(`new follower ${payload.actor} saved`); - }); - + if (!err){ + db.save_follower(payload, function(err, data){ + console.log(`new follower ${payload.actor} saved`); + }); + } res.status(200); }); } else if (payload.type === 'Undo'){ bot.accept(payload, function(err, payload, data){ - db.remove_follower(payload, function(err, data){ - console.log(`removed follower ${payload.actor}`); - }); + if (!err){ + db.remove_follower(payload, function(err, data){ + console.log(`removed follower ${payload.actor}`); + }); + } + res.status(200); + }); + } + else if (payload.type === 'Create'){ + bot.accept(payload, function(err, payload, data){ + if (!err && payload.object && payload.object.content){ + var dom = new JSDOM(`
${payload.object.content}
`), + message_body = ''; + try { + message_body = dom.window.document.body.firstChild.textContent; + + } catch(err){ /* noop */} + bot.compose_reply({ + payload: payload, + message_from: payload.actor, + message_body: message_body, + }, function(err, reply_message){ + if (!err){ + console.log(err); + console.log('sending reply...'); + bot.send_reply({ + payload: payload, + message_body: message_body, + reply_message: reply_message + }, function(err, data){ + + }); + } + }); + } res.status(200); }); } @@ -44,7 +82,7 @@ router.post('/', function (req, res) { } else{ console.log('payload', payload); - res.status(200); + res.status(200); } }); diff --git a/routes/index.js b/routes/index.js index 1b5722c..b362a88 100644 --- a/routes/index.js +++ b/routes/index.js @@ -3,7 +3,7 @@ var express = require('express'), router = express.Router(), moment = require('moment'), db = require(__dirname + '/../helpers/db.js'), - bot = require(__dirname + '/../bot.js'); + bot = require(__dirname + '/../bot/bot.js'); router.get('/', function (req, res) { // console.log(req.headers); @@ -22,6 +22,8 @@ router.get('/', function (req, res) { }, function(err, data){ // console.log(posts); + var no_posts = false; + if (data && data.posts && data.posts.length > 0){ data.posts.forEach(function(post){ post.date_formatted = moment(post.date).fromNow(); @@ -29,6 +31,8 @@ router.get('/', function (req, res) { post.attachment = JSON.parse(post.attachment); } catch(err){ /*noop*/ } }); + } else { + no_posts = true; } var show_next_page = false, @@ -42,6 +46,8 @@ router.get('/', function (req, res) { show_previous_page = true; } + console.log(data.page_count, data.page_count > 1) + res.render('../views/home.handlebars', { project_name: process.env.PROJECT_DOMAIN, bot_url: `https://${process.env.PROJECT_DOMAIN}.glitch.me/`, @@ -54,6 +60,7 @@ router.get('/', function (req, res) { post_count: data.post_count, page_count: data.page_count, posts: data.posts, + no_posts: no_posts, current_page: page, show_pagination: data.page_count > 1, next_page: page + 1, diff --git a/routes/outbox.js b/routes/outbox.js index 0434ffc..8078b94 100644 --- a/routes/outbox.js +++ b/routes/outbox.js @@ -1,7 +1,7 @@ var fs = require('fs'), url = require('url'), util = require('util'), - bot = require(__dirname + '/../bot.js'); + bot = require(__dirname + '/../bot/bot.js'); var express = require('express'), router = express.Router(); diff --git a/routes/pubsub.js b/routes/pubsub.js index 3ee1a49..bae74c5 100644 --- a/routes/pubsub.js +++ b/routes/pubsub.js @@ -1,7 +1,7 @@ var fs = require('fs'), url = require('url'), util = require('util'), - bot = require(__dirname + '/../bot.js'); + bot = require(__dirname + '/../bot/bot.js'); var express = require('express'), router = express.Router(); diff --git a/routes/salmon.js b/routes/salmon.js index fef2bd8..1db92e9 100644 --- a/routes/salmon.js +++ b/routes/salmon.js @@ -1,7 +1,7 @@ var fs = require('fs'), url = require('url'), util = require('util'), - bot = require(__dirname + '/../bot.js'); + bot = require(__dirname + '/../bot/bot.js'); var express = require('express'), router = express.Router(); diff --git a/routes/webhook.js b/routes/webhook.js index adb63dc..1937139 100644 --- a/routes/webhook.js +++ b/routes/webhook.js @@ -1,7 +1,7 @@ var fs = require('fs'), url = require('url'), util = require('util'), - bot = require(__dirname + '/../bot.js'); + bot = require(__dirname + '/../bot/bot.js'); var express = require('express'), router = express.Router(); diff --git a/routes/well-known.js b/routes/well-known.js index e7c9881..848f08e 100644 --- a/routes/well-known.js +++ b/routes/well-known.js @@ -1,7 +1,7 @@ var fs = require('fs'), url = require('url'), util = require('util'), - bot = require(__dirname + '/../bot.js'); + bot = require(__dirname + '/../bot/bot.js'); var express = require('express'), router = express.Router(); diff --git a/server.js b/server.js index 7cb9acb..b537f75 100644 --- a/server.js +++ b/server.js @@ -2,14 +2,23 @@ var app = require(__dirname + '/app.js'), load_keys = require(__dirname + '/helpers/keys.js'), db = require(__dirname + '/helpers/db.js'); +db.init(); + // db.drop_table('Posts'); // db.drop_table('Followers'); +// db.drop_table('Events'); // db.get_followers(function(err, data){ -// console.log(data); +// console.log('Followers:', data); // }); -db.init(); +// db.get_posts(function(err, data){ +// console.log('Posts:', data); +// }); + +// db.get_events(function(err, data){ +// console.log('Events:', data); +// }); var listener = app.listen(process.env.PORT, function() { console.log(`app is running on port ${listener.address().port}...`); diff --git a/sessions b/sessions deleted file mode 100644 index b4fc7e2130314df79b53a7177440b1a49f0f441e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 147456 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.4.0' + resolution: + integrity: sha512-ugTb7Lq7u4GfWSqqpwE0bGyoBZNMTok/zDBXxfEG0QM50jNlGhIWjRC1pPN7bvV1anhF+bs+/gNcRw+o55Evbg== /acorn/5.7.3: dev: false engines: @@ -62,6 +80,13 @@ packages: hasBin: true resolution: integrity: sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw== + /acorn/6.0.2: + dev: false + engines: + node: '>=0.4.0' + hasBin: true + resolution: + integrity: sha512-GXmKIvbrN3TV7aVqAzVFaMW8F8wzVX7voEBRO3bDA64+EX37YSayggRJP5Xig6HYHBkWKpFg9W5gg6orklubhg== /activitystrea.ms/2.1.3: dependencies: activitystreams-context: 3.1.0 @@ -176,6 +201,10 @@ packages: node: '>=0.10.0' resolution: integrity: sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ= + /array-equal/1.0.0: + dev: false + resolution: + integrity: sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM= /array-filter/0.0.1: dev: false resolution: @@ -254,6 +283,10 @@ packages: dev: false resolution: integrity: sha1-NhIfhFwFeBct5Bmpfb6x0W7DRUI= + /async-limiter/1.0.0: + dev: false + resolution: + integrity: sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg== /async/1.5.2: dev: false resolution: @@ -841,6 +874,10 @@ packages: hasBin: true resolution: integrity: sha512-erYug8XoqzU3IfcU8fUgyHqyOXqIE4tUTTQ+7mqUjQlvnXkOO6OlT9c/ZoJVHYoAaqGxr09CN53G7XIsO4KtWA== + /browser-process-hrtime/0.1.3: + dev: false + resolution: + integrity: sha512-bRFnI4NnjO6cnyLmOV/7PVoDEMJChlcfN0z4s1YMBY989/SvlfMI1lgCnkFUs53e9gQF+w7qu7XdllSTiSl8Aw== /browser-resolve/1.11.3: dependencies: resolve: 1.1.7 @@ -1441,6 +1478,16 @@ packages: dev: false resolution: integrity: sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg== + /cssom/0.3.4: + dev: false + resolution: + integrity: sha512-+7prCSORpXNeR4/fUP3rL+TzqtiFfhMvTd7uEqMdgPvLPt4+uzFUeufx5RHjGTACCargg/DiEt/moMQmvnfkog== + /cssstyle/1.1.1: + dependencies: + cssom: 0.3.4 + dev: false + resolution: + integrity: sha512-364AI1l/M5TYcFH83JnOH/pSqgaNnKmYgKrm0didZMGKWjQB60dymwWy1rKUgL3J1ffdq9xVi2yGLHdSjjSNog== /currently-unhandled/0.4.1: dependencies: array-find-index: 1.0.2 @@ -1457,6 +1504,14 @@ packages: node: '>=0.10' resolution: integrity: sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA= + /data-urls/1.0.1: + dependencies: + abab: 2.0.0 + whatwg-mimetype: 2.2.0 + whatwg-url: 7.0.0 + dev: false + resolution: + integrity: sha512-0HdcMZzK6ubMUnsMmQmG0AcLQPvbvb47R0+7CCZQCYgcd8OUWG91CG7sM6GoXgjz+WLl4ArFzHtBMy/QqSF4eg== /date-now/0.1.4: dev: false resolution: @@ -1485,6 +1540,10 @@ packages: node: '>=4.0.0' resolution: integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== + /deep-is/0.1.3: + dev: false + resolution: + integrity: sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ= /define-properties/1.1.3: dependencies: object-keys: 1.0.12 @@ -1621,6 +1680,12 @@ packages: npm: '>=1.2' resolution: integrity: sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA== + /domexception/1.0.1: + dependencies: + webidl-conversions: 4.0.2 + dev: false + resolution: + integrity: sha512-raigMkn7CJNNo6Ihro1fzG7wr3fHuYVytzquZKX5n0yizGsTcYgzdIUwj1X9pK0VvjeihV+XiclP+DjwbsSKug== /duplexer2/0.1.4: dependencies: readable-stream: 2.3.6 @@ -1701,6 +1766,33 @@ packages: node: '>=0.8.0' resolution: integrity: sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= + /escodegen/1.11.0: + dependencies: + esprima: 3.1.3 + estraverse: 4.2.0 + esutils: 2.0.2 + optionator: 0.8.2 + dev: false + engines: + node: '>=4.0' + hasBin: true + optionalDependencies: + source-map: 0.6.1 + resolution: + integrity: sha512-IeMV45ReixHS53K/OmfKAIztN/igDHzTJUhZM3k1jMhIZWjk45SMwAtBsEXiJp3vSPmTcu6CXn7mDvFHRN66fw== + /esprima/3.1.3: + dev: false + engines: + node: '>=4' + hasBin: true + resolution: + integrity: sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM= + /estraverse/4.2.0: + dev: false + engines: + node: '>=0.10.0' + resolution: + integrity: sha1-De4/7TH81GlhjOc0IJn8GvoL2xM= /esutils/2.0.2: dev: false engines: @@ -1900,6 +1992,10 @@ packages: dev: false resolution: integrity: sha1-1RQsDK7msRifh9OnYREGT4bIu/I= + /fast-levenshtein/2.0.6: + dev: false + resolution: + integrity: sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= /filename-regex/2.0.1: dev: false engines: @@ -2292,6 +2388,12 @@ packages: dev: false resolution: integrity: sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w== + /html-encoding-sniffer/1.0.2: + dependencies: + whatwg-encoding: 1.0.5 + dev: false + resolution: + integrity: sha512-71lZziiDnsuabfdYiUeWdCVyKuqwWi23L8YeIgV9jSSZHCtb6wB1BKWooH7L3tn4/FuZJMVWyNaIDr4RGmaSYw== /htmlescape/1.1.1: dev: false engines: @@ -2692,6 +2794,38 @@ packages: optional: true resolution: integrity: sha1-peZUwuWi3rXyAdls77yoDA7y9RM= + /jsdom/12.1.0: + dependencies: + abab: 2.0.0 + acorn: 5.7.3 + acorn-globals: 4.3.0 + array-equal: 1.0.0 + cssom: 0.3.4 + cssstyle: 1.1.1 + data-urls: 1.0.1 + domexception: 1.0.1 + escodegen: 1.11.0 + html-encoding-sniffer: 1.0.2 + nwsapi: 2.0.9 + parse5: 5.1.0 + pn: 1.1.0 + request: 2.88.0 + request-promise-native: /request-promise-native/1.0.5/request@2.88.0 + saxes: 3.1.3 + symbol-tree: 3.2.2 + tough-cookie: 2.4.3 + w3c-hr-time: 1.0.1 + webidl-conversions: 4.0.2 + whatwg-encoding: 1.0.5 + whatwg-mimetype: 2.2.0 + whatwg-url: 7.0.0 + ws: 6.0.0 + xml-name-validator: 3.0.0 + dev: false + engines: + node: '>=8' + resolution: + integrity: sha512-1lrrgWhI5zN5B5p88xihrhfeAbdagMUXEN8Z+8l5f33k5IMZYDxIDJaPXKOOBF4xAt6hVyE/HrBbUYGjSrZlvg== /jsesc/0.5.0: dev: false hasBin: true @@ -2829,6 +2963,15 @@ packages: node: '>=0.10.0' resolution: integrity: sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU= + /levn/0.3.0: + dependencies: + prelude-ls: 1.1.2 + type-check: 0.3.2 + dev: false + engines: + node: '>= 0.8.0' + resolution: + integrity: sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4= /load-json-file/1.1.0: dependencies: graceful-fs: 4.1.11 @@ -2858,6 +3001,10 @@ packages: dev: false resolution: integrity: sha512-eWw5r+PYICtEBgrBE5hhlT6aAa75f411bgDz/ZL2KZqYV03USvucsxcHUIlGTDTECs1eunpI7HOV7U+WLDvNdQ== + /lodash.sortby/4.7.0: + dev: false + resolution: + integrity: sha1-7dFMgk4sycHgsKG0K7UhBRakJDg= /lodash/3.10.1: dev: false resolution: @@ -3418,6 +3565,10 @@ packages: node: '>=0.10.0' resolution: integrity: sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0= + /nwsapi/2.0.9: + dev: false + resolution: + integrity: sha512-nlWFSCTYQcHk/6A9FFnfhKc14c3aFhfdNBXgo8Qgi9QTBu/qg3Ww+Uiz9wMzXd1T8GFxPc2QIHB6Qtf2XFryFQ== /oauth-sign/0.8.2: dev: false resolution: @@ -3511,6 +3662,19 @@ packages: dev: false resolution: integrity: sha1-2j6nRob6IaGaERwybpDrFaAZZoY= + /optionator/0.8.2: + dependencies: + deep-is: 0.1.3 + fast-levenshtein: 2.0.6 + levn: 0.3.0 + prelude-ls: 1.1.2 + type-check: 0.3.2 + wordwrap: 1.0.0 + dev: false + engines: + node: '>= 0.8.0' + resolution: + integrity: sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q= /os-browserify/0.1.2: dev: false resolution: @@ -3597,6 +3761,10 @@ packages: node: '>=0.10.0' resolution: integrity: sha1-9ID0BDTvgHQfhGkJn43qGPVaTck= + /parse5/5.1.0: + dev: false + resolution: + integrity: sha512-fxNG2sQjHvlVAYmzBZS9YlDp6PTSSDwa98vkD4QgVDDCAo84z5X1t5XyJQ62ImdLXx5NdIIfihey6xpum9/gRQ== /parseurl/1.3.2: dev: false engines: @@ -3710,12 +3878,22 @@ packages: node: '>= 0.4.0' resolution: integrity: sha1-tUGO8EOd5UJfxJlQQtztFPsqhP8= + /pn/1.1.0: + dev: false + resolution: + integrity: sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA== /posix-character-classes/0.1.1: dev: false engines: node: '>=0.10.0' resolution: integrity: sha1-AerA/jta9xoqbAL+q7jB/vfgDqs= + /prelude-ls/1.1.2: + dev: false + engines: + node: '>= 0.8.0' + resolution: + integrity: sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ= /prepare-response/1.1.3: dependencies: mime: 1.6.0 @@ -3798,6 +3976,12 @@ packages: dev: false resolution: integrity: sha1-wNWmOycYgArY4esPpSachN1BhF4= + /punycode/2.1.1: + dev: false + engines: + node: '>=6' + resolution: + integrity: sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== /qs/6.5.1: dev: false engines: @@ -4047,6 +4231,32 @@ packages: node: '>=0.10.0' resolution: integrity: sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo= + /request-promise-core/1.1.1/request@2.88.0: + dependencies: + lodash: 4.17.11 + request: 2.88.0 + dev: false + engines: + node: '>=0.10.0' + id: registry.npmjs.org/request-promise-core/1.1.1 + peerDependencies: + request: ^2.34 + resolution: + integrity: sha1-Pu4AssWqgyOc+wTFcA2jb4HNCLY= + /request-promise-native/1.0.5/request@2.88.0: + dependencies: + request: 2.88.0 + request-promise-core: /request-promise-core/1.1.1/request@2.88.0 + stealthy-require: 1.1.1 + tough-cookie: 2.4.3 + dev: false + engines: + node: '>=0.12.0' + id: registry.npmjs.org/request-promise-native/1.0.5 + peerDependencies: + request: ^2.34 + resolution: + integrity: sha1-UoF3D2jgyXGeUWP9P6tIIhX0/aU= /request/2.87.0: dependencies: aws-sign2: 0.7.0 @@ -4196,6 +4406,12 @@ packages: dev: false resolution: integrity: sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== + /saxes/3.1.3: + dependencies: + xmlchars: 1.3.1 + dev: false + resolution: + integrity: sha512-Nc5DXc5A+m3rUDtkS+vHlBWKT7mCKjJPyia7f8YMW773hsXVv2wEHQZGE0zs4+5PLwz9U5Sbl/94Cnd9vHV7Bg== /scss-tokenizer/0.2.3: dependencies: js-base64: 2.4.9 @@ -4484,6 +4700,12 @@ packages: dev: false resolution: integrity: sha512-j4emi03KXqJWcIeF8eIXkjMFN1Cmb8gUlDYGeBALLPo5qdyTfA9bOtl8m33lRoC+vFMkP3gl0WsDr6+gzxbbTA== + /stealthy-require/1.1.1: + dev: false + engines: + node: '>=0.10.0' + resolution: + integrity: sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks= /stream-browserify/2.0.1: dependencies: inherits: 2.0.3 @@ -4595,6 +4817,10 @@ packages: node: '>=0.8.0' resolution: integrity: sha1-U10EXOa2Nj+kARcIRimZXp3zJMc= + /symbol-tree/3.2.2: + dev: false + resolution: + integrity: sha1-rifbOPZgp64uHDt9G8KQgZuFGeY= /syntax-error/1.4.0: dependencies: acorn-node: 1.5.2 @@ -4706,6 +4932,12 @@ packages: node: '>=0.8' resolution: integrity: sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ== + /tr46/1.0.1: + dependencies: + punycode: 2.1.1 + dev: false + resolution: + integrity: sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk= /tracery-grammar/2.7.3: dev: false resolution: @@ -4743,6 +4975,14 @@ packages: optional: true resolution: integrity: sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q= + /type-check/0.3.2: + dependencies: + prelude-ls: 1.1.2 + dev: false + engines: + node: '>= 0.8.0' + resolution: + integrity: sha1-WITKtRLPHTVeP7eE8wgEsrUg23I= /type-is/1.6.16: dependencies: media-typer: 0.3.0 @@ -4969,6 +5209,12 @@ packages: dev: false resolution: integrity: sha512-OIon2MWA21ZO42UBsTa5DuMsk5zv72DxMdQNvLsPN1M9GrjVTovn3LgWUZdPVnKBpdWhqWV7Mfbq/Sh0vkHIBw== + /w3c-hr-time/1.0.1: + dependencies: + browser-process-hrtime: 0.1.3 + dev: false + resolution: + integrity: sha1-gqwr/2PZUOqeMYmlimViX+3xkEU= /watchify/3.11.0: dependencies: anymatch: 1.3.2 @@ -4982,6 +5228,28 @@ packages: hasBin: true resolution: integrity: sha512-7jWG0c3cKKm2hKScnSAMUEUjRJKXUShwMPk0ASVhICycQhwND3IMAdhJYmc1mxxKzBUJTSF5HZizfrKrS6BzkA== + /webidl-conversions/4.0.2: + dev: false + resolution: + integrity: sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg== + /whatwg-encoding/1.0.5: + dependencies: + iconv-lite: 0.4.24 + dev: false + resolution: + integrity: sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw== + /whatwg-mimetype/2.2.0: + dev: false + resolution: + integrity: sha512-5YSO1nMd5D1hY3WzAQV3PzZL83W3YeyR1yW9PcH26Weh1t+Vzh9B6XkDh7aXm83HBZ4nSMvkjvN2H2ySWIvBgw== + /whatwg-url/7.0.0: + dependencies: + lodash.sortby: 4.7.0 + tr46: 1.0.1 + webidl-conversions: 4.0.2 + dev: false + resolution: + integrity: sha512-37GeVSIJ3kn1JgKyjiYNmSLP1yzbpb29jdmwBSgkD9h40/hyrR/OifpVUndji3tmwGgD8qpw7iQu3RSbCrBpsQ== /which-module/1.0.0: dev: false resolution: @@ -5017,6 +5285,10 @@ packages: node: '>=0.4.0' resolution: integrity: sha1-o9XabNXAvAAI03I0u68b7WMFkQc= + /wordwrap/1.0.0: + dev: false + resolution: + integrity: sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus= /wrap-ansi/2.1.0: dependencies: string-width: 1.0.2 @@ -5031,10 +5303,24 @@ packages: dev: false resolution: integrity: sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= + /ws/6.0.0: + dependencies: + async-limiter: 1.0.0 + dev: false + resolution: + integrity: sha512-c2UlYcAZp1VS8AORtpq6y4RJIkJ9dQz18W32SpR/qXGfLDZ2jU4y4wKvvZwqbi7U6gxFQTeE+urMbXU/tsDy4w== + /xml-name-validator/3.0.0: + dev: false + resolution: + integrity: sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw== /xml/1.0.1: dev: false resolution: integrity: sha1-eLpyAgApxbyHuKgaPPzXS0ovweU= + /xmlchars/1.3.1: + dev: false + resolution: + integrity: sha512-tGkGJkN8XqCod7OT+EvGYK5Z4SfDQGD30zAa58OcnAa0RRWgzUEK72tkXhsX1FZd+rgnhRxFtmO+ihkp8LHSkw== /xmldom/0.1.19: dev: false engines: @@ -5117,6 +5403,7 @@ specifiers: express-session: ^1.15.6 generate-rsa-keypair: ^0.1.2 gifencoder: ^1.1.0 + jsdom: ^12.1.0 momentjs: ^2.0.0 neocities: ^0.0.3 node-openssl-cert: ^0.0.47 diff --git a/src/styles/_layout.scss b/src/styles/_layout.scss index 68b396d..fe809c4 100644 --- a/src/styles/_layout.scss +++ b/src/styles/_layout.scss @@ -1,6 +1,5 @@ -#about-bot.jumbotron{ - border-top-left-radius: 0; - border-top-right-radius: 0; +body{ + background: #eff0f2; } main{ @@ -11,3 +10,42 @@ main{ img{ max-width: 100%; } + +blockquote{ + /* Courtesy of css-tricks.com. */ + background: #f9f9f9; + border-left: 10px solid #ccc; + // max-width: $max-content-width; + margin: 2em auto; + padding: 0.5em 1em 1em 0; + quotes: "\201C""\201D""\2018""\2019"; + + .col-md-6 &{ + padding: 1em; + } + + &:before { + color: #ccc; + content: '“'; + font-size: 4em; + line-height: 0.1em; + margin-right: 0.25em; + vertical-align: -0.4em; + } + + p { + line-height: 1.5em; + padding: 0 40px; + } +} + +.card-footer{ + a.post-date{ + color: #6c757d; + } +} + +#about-bot.jumbotron{ + border-top-left-radius: 0; + border-top-right-radius: 0; +} diff --git a/views/home.handlebars b/views/home.handlebars index bee948a..720692c 100644 --- a/views/home.handlebars +++ b/views/home.handlebars @@ -1,6 +1,11 @@
{{> header }} + {{#if no_posts}} +

This bot hasn't posted yet.

+ {{/if}} + + {{#each posts}}
{{#if this.attachment}} @@ -11,13 +16,13 @@ {{#equals this.type "Note"}}
-

{{this.content}}

+

{{{this.content}}}

{{/equals}}
diff --git a/views/post.handlebars b/views/post.handlebars index c4a9523..ce6019e 100644 --- a/views/post.handlebars +++ b/views/post.handlebars @@ -5,7 +5,7 @@
{{post.date}}
{{#if post.content}} -

{{post.content}}

+

{{{post.content}}}

{{/if}} {{#each post.attachment}} @@ -16,9 +16,9 @@ {{/equals}}

- Main page + Main page {{#if is_admin}} - Delete + Delete {{/if}}