did some commenting (I barely commented anything)

This commit is contained in:
deadvey 2025-07-13 02:01:09 +01:00
parent 3a821b5eba
commit 4fb12c54f8
3 changed files with 108 additions and 31 deletions

View File

@ -17,8 +17,37 @@ In action on my website: [deadvey.com](https://deadvey.com)<br/>
* probably scales like shit
* probably insecure as hell
# planned features
# planned features/todo list
* atom
* federation
* federation (looks tricky)
* sign up
* All strings (including in edit and post page) customisable
* split code into files to tidy it up a bit
* inline comments and docs
* give each post a hard postID to prevent potential issues
* clean up code a bit
# format indicators
* %% - A literal %
* %A - List of tags
* %B - List of tags, each one with a hyperlink to that tag page
* %C - Post content
* %D - Published date in the format specified by date_format
* %E - Edited date in the format specified by date_format
* %F - Pretty name
* %G - Tag name (used for the tag page only)
* %H - Frontpage hit count
* %I - User description
* %L - URL Permanent link to the post
* %M - comments
* %N - the username of the user (poster)
* %P - URL to create a new post
* %O - URL to edit this post
* %R - Site wide RSS feed
* %S - post seperator as defined by post_seperator
* %T - Title
* %U - URL the the user (poster)
* %W - Site Description as defined by site_description
* %X - Comment submission box
* %Y - Site Name as defined by site_name
* %Z - Attribution (to me) and source code link and license

104
app.js
View File

@ -1,46 +1,64 @@
const fs = require('fs');
const express = require('express');
const showdown = require('showdown')
const crypto = require('crypto'); // For encrypting passwords
// Get the libraries
const fs = require('fs'); // For modifying and reading files
const express = require('express'); // For running a webserver in nodejs
const showdown = require('showdown') // For converting markdown to html on demand, https://showdownjs.com/
const crypto = require('crypto'); // For encrypting passwords, I use sha512
// fromUnixTime creates a date object out of an integer
// format is used to format a date object into a defined format eg yyyy-MM-dd
// getUnixTime converts a date object into an integer (unix time)
// find out more at https://date-fns.org/ \or docs: https://date-fns.org/docs/Getting-Started
const { fromUnixTime, format, getUnixTime } = require("date-fns")
// There's only one possible argument, so we can just check if the user passed that one
// TODO I plan on adding more such as --help and --post so I should make this more robust at some point
if (process.argv[2] == "--first-time") {
initialise()
initialise() // Creates any files such users.js, posts.js, comments.js or config.js if they are not present
}
let users
let posts
// Define the modules now so they are global
let users // contains a list of users, each user is an object containing username,prettyname,hash and description
let posts // contains a list of posts,
let comments
let config
try {
users = require('./users.js');
// We're going to try and import the modules, users = require('./users.js');
posts = require('./posts.js');
comments = require('./comments.js');
config = require('./config.js');
}
catch (error) {
// if they don't all import then
// inform the user to pass --first-time and exit with an error code
console.log("A file is missing!")
console.log("Run with --first-time to initialise the program")
console.log(error)
process.exit(1)
}
let converter = new showdown.Converter({
simpleLineBreaks: true,
tables: true,
strikethrough: true,
tasklists: true,
encodeEmails: true
})
const app = express();
// https://showdownjs.com/docs/available-options
let converter = new showdown.Converter({
simpleLineBreaks: true, // Parse line breaks as <br/> in paragraphs (GitHub-style behavior).
tables: true, // Enable support for tables syntax.
strikethrough: true, // Enable support for strikethrough: ~~text~~
tasklists: true, // Enable support for GitHub style tasklists. - [x] and - [ ]
encodeEmails: true //Enable automatic obfuscation of email addresses. emails are encoded via character entities
})
// The footer div is globale because it's a site wide, so define it here
let footer_div = config.site_wide_footer
footer_div = replace_format_indicators(footer_div)
// Define stuff to do with express (nodejs webserver)
const app = express();
app.use(express.urlencoded({ extended: true }));
app.use(express.json());
app.use(express.static(config.root_path));
// Initialise the program by creating users.js, comments.js, posts.js and config.js
// All require default content in them to start off with
// Then exit successfully
// returns nothing
function initialise() {
try {
const users = require("./users.js");
@ -73,18 +91,28 @@ function initialise() {
console.log("Error copying file")
})
}
console.log("Successfully initialised")
process.exit(0)
}
// The users are stored as a list of objects [ user_object, user_object, user_object ]
// So you cannot easily find the userID (position in list) from the username
// This function returns the username for a given userID by looping over every user
// if the user is present, it returns the index of the user (integer)
// if the user is not present it returns -1
function get_userID(username) {
for (let i = 0; i < users.users.length; i++) {
for (let i = 0; i < users.users.length; i++) { // Loop over every user
if (users.users[i]['username'] == username) {
return i
return i // If the username matches then return the index of that user
}
}
return -1
return -1 // If user is not present, return -1
}
// The configuration defines a date format using the date-fns syntax
// this converts unix time (an integer) into a string that is formatted according to config.js
// uses date-fns's fromUnixTime() and format()
// returns the formatted date (string)
function unix_time_to_date_format(unix_time) {
date = fromUnixTime(unix_time)
formatted_date = format(date, config.date_format)
@ -92,26 +120,41 @@ function unix_time_to_date_format(unix_time) {
return formatted_date
}
// This is similar to the above function, however, instead of formatting to the users
// configuration, it formats to RFC-822 which is the date format used by RSS feeds
// eg "Mon, 23 May 2025 18:59:59 +0100"
// returns the formatted date (string)
function unix_time_to_rss_date(unix_time) {
date = fromUnixTime(unix_time)
formatted_date = format(date, "EEE, dd MMM yyyy HH:mm:ss")
return `${formatted_date} ${config.time_zone}`
}
// This function accepts a list of strings eg ["string1","string2,"string3"] (any length)
// then returns a string of them each pointing to a seperate url
// eg "<a href="/tag/string1">string1</a>, <a href="/tag/string2">string2</a>, <a href="/tag/string3">string3</a>
// this is so you can have a list of tags that each point to their individual tag page
// returns: string
function hyperlink_tags(tags) {
string = ""
for (let tag_index = 0; tag_index < tags.length; tag_index++) {
string += `<a href="/tag/${tags[tag_index]}">${tags[tag_index]}</a>`
if (tag_index < tags.length - 1) {
string = "" // Initialises the string
for (let tag_index = 0; tag_index < tags.length; tag_index++) { // Loop over each tag
string += `<a href="/tag/${tags[tag_index]}">${tags[tag_index]}</a>` // Adds the tag to the string as a HTML href
if (tag_index < tags.length - 1) { // If there are more tags, then insert a comma
string += ", ";
}
}
return string
}
function replace_format_indicators(input_string, post_index=0, tag_name="tag") {
post_object = posts.posts[post_index]
output_string = input_string
// See the readme format indicators section for a full list of format indicators
// This function replaces the format indicators in a template to the content they represent
// accepts the template (string),
// the post index (int) as an optional paramter to indicate what post is to be used (for replacing things like content and titles)
// the tag (strig) as an optional parameter to indicate what tag is being used (for /tag/:tag pages)
// returns the template with it's format indiactors replaced (string)
function replace_format_indicators(template, post_index=0, tag_name="tag") {
post_object = posts.posts[post_index] // Defines the post object for easy reference
output_string = template // These should always be replaceable
.replaceAll("%%", "&#37;")
.replaceAll("%P", "/post")
.replaceAll("%O", `/edit/${post_index}`)
@ -119,7 +162,7 @@ function replace_format_indicators(input_string, post_index=0, tag_name="tag") {
.replaceAll("%Y", config.site_name)
.replaceAll("%W", config.site_description)
.replaceAll("%Z", config.attribution)
if (posts.posts.length > 0) {
if (posts.posts.length > 0) { // These can only be replaced if there are more than 0 posts in the posts list
output_string = output_string
.replaceAll("%A", (post_object["tags"]))
.replaceAll("%B", (hyperlink_tags(post_object["tags"])))
@ -142,7 +185,7 @@ function replace_format_indicators(input_string, post_index=0, tag_name="tag") {
<button type="submit">Submit</button>
</form>`)
}
if (config.enable_hitcount == true) {
if (config.enable_hitcount == true) { // Finally, the hitcounter should only be replaced if config.enable_hitcount is true
output_string = output_string
.replaceAll("%H", fs.readFileSync('hitcount.txt'))
}
@ -150,6 +193,10 @@ function replace_format_indicators(input_string, post_index=0, tag_name="tag") {
return output_string
}
// This escapes some potentially dangerous HTML characters with their HTML entities
// https://www.freeformatter.com/html-entities.html
// accepts a string
// returns a string with some character replaced by their entities
function escape_input(input) {
let output = input
.replaceAll("<", "&lt;")
@ -158,6 +205,7 @@ function escape_input(input) {
.replaceAll('"', "&#34;")
.replaceAll("'", "&#39;")
.replaceAll("/", "&#47;")
.replaceAll("%", "&#37;")
return output
}

View File

@ -1 +1 @@
248
253