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
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**
+
+
+
+# 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 b4fc7e2..0000000
Binary files a/sessions and /dev/null differ
diff --git a/shrinkwrap.yaml b/shrinkwrap.yaml
index aaeecb4..e9f2079 100644
--- a/shrinkwrap.yaml
+++ b/shrinkwrap.yaml
@@ -10,6 +10,7 @@ dependencies:
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
@@ -28,6 +29,10 @@ packages:
hasBin: true
resolution:
integrity: sha512-Y7vfi3I5oMOYIr+WxV8NZxDSwcbNgzdKYsTNInmycOq9bUYwGg9ryu57Wg5NLmCjqdFPNUmpMBo3kSJN9tCbXg==
+ /abab/2.0.0:
+ dev: false
+ resolution:
+ integrity: sha512-sY5AXXVZv4Y1VACTtR11UJCPHHudgY5i26Qj5TypE6DKlIApbwb5uqhXcJ5UUGbvZNRh7EeIoW+LrJumBsKp7w==
/abbrev/1.1.1:
dev: false
resolution:
@@ -47,6 +52,13 @@ packages:
dev: false
resolution:
integrity: sha512-zVWV8Z8lislJoOKKqdNMOB+s6+XV5WERty8MnKBeFgwA+19XJjJHs2RP5dzM57FftIs+jQnRToLiWazKr6sSWg==
+ /acorn-globals/4.3.0:
+ dependencies:
+ acorn: 6.0.2
+ acorn-walk: 6.1.0
+ dev: false
+ resolution:
+ integrity: sha512-hMtHj3s5RnuhvHPowpBYvJVj3rAar82JiDQHvGs1zO0l10ocX/xEdBShNHTJaboucJUsScghp74pH3s7EnHHQw==
/acorn-node/1.5.2:
dependencies:
acorn: 5.7.3
@@ -55,6 +67,12 @@ packages:
dev: false
resolution:
integrity: sha512-krFKvw/d1F17AN3XZbybIUzEY4YEPNiGo05AfP3dBlfVKrMHETKpgjpuZkSF8qDNt9UkQcqj7am8yJLseklCMg==
+ /acorn-walk/6.1.0:
+ dev: false
+ engines:
+ node: '>=0.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}}