commenting
This commit is contained in:
parent
b241a80963
commit
bcaa3487dd
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,5 +1,6 @@
|
|||||||
node_modules
|
node_modules
|
||||||
package-lock.json
|
package-lock.json
|
||||||
posts.js
|
posts.js
|
||||||
|
comments.js
|
||||||
users.js
|
users.js
|
||||||
*.swp
|
*.swp
|
||||||
|
@ -9,9 +9,13 @@ In action on my website: [deadvey.com](https://deadvey.com)<br/>
|
|||||||
* rss
|
* rss
|
||||||
* timeline, user page, post page and tag specific page
|
* timeline, user page, post page and tag specific page
|
||||||
* edit/delete posts
|
* edit/delete posts
|
||||||
* probably insecure as hell
|
|
||||||
* hitcount
|
* hitcount
|
||||||
* Markdown syntax in posts
|
* Markdown syntax in posts
|
||||||
|
* Commenting on posts
|
||||||
|
|
||||||
|
# Bugs
|
||||||
|
* probably scales like shit
|
||||||
|
* probably insecure as hell
|
||||||
|
|
||||||
# planned features
|
# planned features
|
||||||
* atom
|
* atom
|
||||||
|
68
app.js
68
app.js
@ -3,14 +3,17 @@ const showdown = require('showdown')
|
|||||||
const crypto = require('crypto'); // For encrypting passwords
|
const crypto = require('crypto'); // For encrypting passwords
|
||||||
const { fromUnixTime, format, getUnixTime } = require("date-fns")
|
const { fromUnixTime, format, getUnixTime } = require("date-fns")
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
|
|
||||||
const users = require('./users.js');
|
const users = require('./users.js');
|
||||||
const posts = require('./posts.js');
|
const posts = require('./posts.js');
|
||||||
|
const comments = require('./comments.js');
|
||||||
const config = require('./config.js');
|
const config = require('./config.js');
|
||||||
let converter = new showdown.Converter({simpleLineBreaks: true, tables: true, strikethrough: true, tasklists: true, encodeEmails: true})
|
let converter = new showdown.Converter({simpleLineBreaks: true, tables: true, strikethrough: true, tasklists: true, encodeEmails: true})
|
||||||
const app = express();
|
const app = express();
|
||||||
let footer_div = config.site_wide_footer
|
let footer_div = config.site_wide_footer
|
||||||
footer_div = replace_format_indicators(footer_div)
|
footer_div = replace_format_indicators(footer_div)
|
||||||
|
|
||||||
|
|
||||||
app.use(express.urlencoded({ extended: true }));
|
app.use(express.urlencoded({ extended: true }));
|
||||||
app.use(express.json());
|
app.use(express.json());
|
||||||
app.use(express.static(config.root_path));
|
app.use(express.static(config.root_path));
|
||||||
@ -61,6 +64,7 @@ function replace_format_indicators(input_string, post_index=0, tag_name="tag") {
|
|||||||
.replaceAll("%G", tag_name)
|
.replaceAll("%G", tag_name)
|
||||||
.replaceAll("%I", users.users[post_object['userID']]['description'])
|
.replaceAll("%I", users.users[post_object['userID']]['description'])
|
||||||
.replaceAll("%L", `/post/${post_index}`)
|
.replaceAll("%L", `/post/${post_index}`)
|
||||||
|
.replaceAll("%M", return_comments(post_index))
|
||||||
.replaceAll("%N", users.users[post_object["userID"]]['username'])
|
.replaceAll("%N", users.users[post_object["userID"]]['username'])
|
||||||
.replaceAll("%P", "/post")
|
.replaceAll("%P", "/post")
|
||||||
.replaceAll("%O", `/edit/${post_index}`)
|
.replaceAll("%O", `/edit/${post_index}`)
|
||||||
@ -68,6 +72,12 @@ function replace_format_indicators(input_string, post_index=0, tag_name="tag") {
|
|||||||
.replaceAll("%S", config.seperator)
|
.replaceAll("%S", config.seperator)
|
||||||
.replaceAll("%T", post_object["title"])
|
.replaceAll("%T", post_object["title"])
|
||||||
.replaceAll("%U", `/user/${users.users[post_object["userID"]]['username']}`)
|
.replaceAll("%U", `/user/${users.users[post_object["userID"]]['username']}`)
|
||||||
|
.replaceAll("%X", `<form method="POST" action="/submit_comment">
|
||||||
|
<input type="hidden" name="post_index" value="${post_index}">
|
||||||
|
<input placeholder="username" name="name"><br/>
|
||||||
|
<textarea placeholder="comment" name="content"></textarea><br/>
|
||||||
|
<button type="submit">Submit</button>
|
||||||
|
</form>`)
|
||||||
.replaceAll("%Y", config.site_name)
|
.replaceAll("%Y", config.site_name)
|
||||||
.replaceAll("%W", config.site_description)
|
.replaceAll("%W", config.site_description)
|
||||||
.replaceAll("%Z", config.attribution)
|
.replaceAll("%Z", config.attribution)
|
||||||
@ -90,6 +100,21 @@ function escape_input(input) {
|
|||||||
return output
|
return output
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO make the formatting customisable
|
||||||
|
function return_comments(post_id) {
|
||||||
|
const post_comments = comments.comments[post_id]
|
||||||
|
let comment_content = ""
|
||||||
|
for (let comment_index = 0; comment_index < post_comments.length; comment_index++) {
|
||||||
|
let comment = {...post_comments[comment_index]};
|
||||||
|
comment['content'] = comment['content']
|
||||||
|
.replaceAll(/>> ([0-9]*)/g, "<a href='#$1'>>> $1</a>")
|
||||||
|
.replaceAll("\n", "<br/>")
|
||||||
|
comment_content += `<div id="${comment['id']}">${comment['name']} ${unix_time_to_date_format(comment['pubdate'])} No. ${comment['id']}<br/>${comment['content']}</div><br/>`
|
||||||
|
}
|
||||||
|
return comment_content
|
||||||
|
}
|
||||||
|
|
||||||
|
// RSS protocol gets
|
||||||
app.get(config.rss_path, (req,res) => {
|
app.get(config.rss_path, (req,res) => {
|
||||||
if (config.rss == false) {
|
if (config.rss == false) {
|
||||||
res.send("Sorry, RSS is disabled!")
|
res.send("Sorry, RSS is disabled!")
|
||||||
@ -106,7 +131,7 @@ app.get(config.rss_path, (req,res) => {
|
|||||||
rss_content += `
|
rss_content += `
|
||||||
<item>
|
<item>
|
||||||
<title>${posts.posts[i]["title"]}</title>
|
<title>${posts.posts[i]["title"]}</title>
|
||||||
<link>${config.site_url}/post/${i}.${config.file_extension}</link>
|
<link>${config.site_url}/post/${i}</link>
|
||||||
<description><![CDATA[${converter.makeHtml(posts.posts[i]["content"])}]]></description>
|
<description><![CDATA[${converter.makeHtml(posts.posts[i]["content"])}]]></description>
|
||||||
<guid isPermaLink="true">${config.site_url}/post/${i}</guid>
|
<guid isPermaLink="true">${config.site_url}/post/${i}</guid>
|
||||||
<pubDate>${unix_time_to_rss_date(posts.posts[i]['pubdate'])}</pubDate>`
|
<pubDate>${unix_time_to_rss_date(posts.posts[i]['pubdate'])}</pubDate>`
|
||||||
@ -177,11 +202,11 @@ app.get("/tag/:tag", (req,res) => {
|
|||||||
|
|
||||||
app.get("/post", (req,res) => {
|
app.get("/post", (req,res) => {
|
||||||
res.send(`</html><head><meta charset="${config.charset}"><style>${config.css}</style></head><form action="/submit_post" method="POST">
|
res.send(`</html><head><meta charset="${config.charset}"><style>${config.css}</style></head><form action="/submit_post" method="POST">
|
||||||
<label>Username: </label><input required name="username"><br/>
|
<input placeholder="username" required name="username"><br/>
|
||||||
<label>Password: </label><input type="password" required id="password" name="password"><br/>
|
<input placeholder="password" type="password" required id="password" name="password"><br/>
|
||||||
<label>Title: </label><input required name="title"><br/>
|
<input placeholder="title" required name="title"><br/>
|
||||||
<label>Content*: </label><textarea required name="content"></textarea><br/>
|
<textarea placeholder="post content*" required name="content"></textarea><br/>
|
||||||
<label>Tags (comma seperated): </label><input name="tags"><br/>
|
<input placeholder="Tags (comma seperated)" name="tags"><br/>
|
||||||
<input type="submit" value="Submit"><br/>
|
<input type="submit" value="Submit"><br/>
|
||||||
<small>* Markdown supported</small>
|
<small>* Markdown supported</small>
|
||||||
</form></html>`);
|
</form></html>`);
|
||||||
@ -194,17 +219,34 @@ app.get("/edit/:post_id", (req,res) => {
|
|||||||
<form action="/submit_edit" method="POST" onsubmit="sha512password()">
|
<form action="/submit_edit" method="POST" onsubmit="sha512password()">
|
||||||
<input name="userID" type="hidden" value="${post['userID']}">
|
<input name="userID" type="hidden" value="${post['userID']}">
|
||||||
<input name="postID" type="hidden" value="${post_id}">
|
<input name="postID" type="hidden" value="${post_id}">
|
||||||
<label>${user.prettyname}'s Password: </label><input type="password" required id="password" name="password"><br/>
|
<input placeholder="${user['prettyname']}'s password" type="password" required id="password" name="password"><br/>
|
||||||
<label>Title: </label><input value="${post['title']}" required name="title"><br/>
|
<input placeholder="title" value="${post['title']}" required name="title"><br/>
|
||||||
<label>Content*: </label>
|
<textarea placeholder="content" required name="content">${post['content']}</textarea><br/>
|
||||||
<textarea required name="content">${post['content']}</textarea><br/>
|
<input placeholder="tags (comma seperated)" value="${post['tags']}" name="tags"><br/>
|
||||||
<label>Tags (comma seperated): </label><input value="${post['tags']}" name="tags"><br/>
|
|
||||||
<label>Delete forever (no undo): </label><input name="delete" type="checkbox"><br/>
|
<label>Delete forever (no undo): </label><input name="delete" type="checkbox"><br/>
|
||||||
<input type="submit" value="Submit"><br/>
|
<input type="submit" value="Submit"><br/>
|
||||||
<small>* Markdown supported</small>
|
<small>* Markdown supported</small>
|
||||||
</form></html>`);
|
</form></html>`);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
app.post("/submit_comment", (req,res) => {
|
||||||
|
const unix_timestamp = getUnixTime(new Date())
|
||||||
|
let name = escape_input(req.body.name)
|
||||||
|
if (name == "") {
|
||||||
|
name = config.default_username
|
||||||
|
}
|
||||||
|
new_comment = {
|
||||||
|
"name": name,
|
||||||
|
"content": escape_input(req.body.content),
|
||||||
|
"id": comments.counter,
|
||||||
|
"pubdate": unix_timestamp
|
||||||
|
};
|
||||||
|
let counter = comments.counter+1;
|
||||||
|
comments.comments[req.body.post_index].push(new_comment);
|
||||||
|
fs.writeFileSync(`${__dirname}/comments.js`, `export const comments = ${JSON.stringify(comments.comments)}\nexport const counter = ${counter}`, 'utf-8');
|
||||||
|
|
||||||
|
res.redirect(301,`/post/${req.body.post_index}`)
|
||||||
|
});
|
||||||
app.post("/submit_edit", (req,res) => {
|
app.post("/submit_edit", (req,res) => {
|
||||||
const password = crypto.createHash('sha512').update(req.body.password).digest('hex');
|
const password = crypto.createHash('sha512').update(req.body.password).digest('hex');
|
||||||
const postID = req.body.postID
|
const postID = req.body.postID
|
||||||
@ -225,6 +267,8 @@ app.post("/submit_edit", (req,res) => {
|
|||||||
if (typeof delete_bool != "undefined") {
|
if (typeof delete_bool != "undefined") {
|
||||||
console.log("Deleting post!")
|
console.log("Deleting post!")
|
||||||
posts.posts.splice(postID,1)
|
posts.posts.splice(postID,1)
|
||||||
|
comments.comments.splice(postID,1)
|
||||||
|
fs.writeFileSync(`${__dirname}/comments.js`, `export const comments = ${JSON.stringify(comments.comments)}\nexport const counter = ${comments.counter}`, 'utf-8');
|
||||||
}
|
}
|
||||||
fs.writeFileSync(`${__dirname}/posts.js`, `export const posts = ${JSON.stringify(posts.posts)}`, 'utf-8');
|
fs.writeFileSync(`${__dirname}/posts.js`, `export const posts = ${JSON.stringify(posts.posts)}`, 'utf-8');
|
||||||
res.redirect(302, "/");
|
res.redirect(302, "/");
|
||||||
@ -256,6 +300,8 @@ app.post("/submit_post", (req,res) => {
|
|||||||
"tags": tags,
|
"tags": tags,
|
||||||
})
|
})
|
||||||
fs.writeFileSync(`${__dirname}/posts.js`, `export const posts = ${JSON.stringify(posts.posts)}`, 'utf-8');
|
fs.writeFileSync(`${__dirname}/posts.js`, `export const posts = ${JSON.stringify(posts.posts)}`, 'utf-8');
|
||||||
|
comments.comments.push([])
|
||||||
|
fs.writeFileSync(`${__dirname}/comments.js`, `export const comments = ${JSON.stringify(comments.comments)}\nexport const counter = ${comments.counter}`)
|
||||||
res.redirect(302, "/");
|
res.redirect(302, "/");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
export const seperator = "<hr/>"
|
export const seperator = "<hr/>"
|
||||||
|
export const comment_indent = "| "
|
||||||
export const site_name = "Deadvey's Blog"
|
export const site_name = "Deadvey's Blog"
|
||||||
export const site_url = "https://deadvey.com"
|
export const site_url = "https://deadvey.com"
|
||||||
export const port = 8080
|
export const port = 8080
|
||||||
@ -9,6 +10,9 @@ export const charset = "UTF-8" // Don't change unless you know why
|
|||||||
// Anything in this directory will be in the webroot, so put favicon.ico and anything else here.
|
// Anything in this directory will be in the webroot, so put favicon.ico and anything else here.
|
||||||
export const root_path = "/var/www/deadvey.com/blog"
|
export const root_path = "/var/www/deadvey.com/blog"
|
||||||
|
|
||||||
|
// Default username if no username is inputted in comment submission
|
||||||
|
export const default_username = "Anon"
|
||||||
|
|
||||||
//export const federation = true
|
//export const federation = true
|
||||||
//export const fediverse_url = "deadvey.com"
|
//export const fediverse_url = "deadvey.com"
|
||||||
export const rss = true
|
export const rss = true
|
||||||
@ -31,6 +35,7 @@ export const time_zone = "+0000"
|
|||||||
// %H - Frontpage hit count
|
// %H - Frontpage hit count
|
||||||
// %I - User description
|
// %I - User description
|
||||||
// %L - URL Permanent link to the post
|
// %L - URL Permanent link to the post
|
||||||
|
// %M - comments
|
||||||
// %N - the username of the user (poster)
|
// %N - the username of the user (poster)
|
||||||
// %P - URL to create a new post
|
// %P - URL to create a new post
|
||||||
// %O - URL to edit this post
|
// %O - URL to edit this post
|
||||||
@ -38,6 +43,7 @@ export const time_zone = "+0000"
|
|||||||
// %S - post seperator as defined by post_seperator
|
// %S - post seperator as defined by post_seperator
|
||||||
// %T - Title
|
// %T - Title
|
||||||
// %U - URL the the user (poster)
|
// %U - URL the the user (poster)
|
||||||
|
// %X - Comment submission box
|
||||||
// %Y - Site Name as defined by site_name
|
// %Y - Site Name as defined by site_name
|
||||||
// %W - Site Description as defined by site_description
|
// %W - Site Description as defined by site_description
|
||||||
// %Z - Attribution (to me) and source code link and license
|
// %Z - Attribution (to me) and source code link and license
|
||||||
@ -65,6 +71,9 @@ export const post_page_format = `<h1>%T</h1>
|
|||||||
<a href="%O">Edit Post</a><br/>
|
<a href="%O">Edit Post</a><br/>
|
||||||
<i>Posted: %D</i><br/>
|
<i>Posted: %D</i><br/>
|
||||||
<i>Edited: %E</i>
|
<i>Edited: %E</i>
|
||||||
|
%S
|
||||||
|
%X
|
||||||
|
%M
|
||||||
%S`
|
%S`
|
||||||
export const timeline_post_format = `<h3>%T</h3>
|
export const timeline_post_format = `<h3>%T</h3>
|
||||||
<p>%C</p>
|
<p>%C</p>
|
||||||
|
@ -1 +1 @@
|
|||||||
128
|
228
|
Loading…
x
Reference in New Issue
Block a user