Changed how comments are stored and how data is retrieved

This commit is contained in:
2025-11-27 11:34:12 +00:00
parent ef8711b0e1
commit 7d38752f34
14 changed files with 130 additions and 128 deletions

View File

@@ -21,8 +21,8 @@ Read the [configuation guide](docs/CONFIG.md) for configuration help (in config.
* user creation, modification and deletion via frontend
* multi user
* powerful customisation via EJS
* Configuration via config.json
* site wide and user specific rss, atom
* hitcount
* Markdown syntax in posts
* Commenting on posts and replying to other comments
* site wide custom CSS and strings

View File

@@ -14,7 +14,7 @@ export function increment_hitcount(postID = -1) { // -1 Means it will increment
writedata('hitcount', hitcount);
}
else {
let post = getdata('posts', postID);
let post = getdata('posts','id', postID);
if (typeof post.hitcount != 'undefined') {
post.hitcount += 1;
writedata('posts', post, postID)
@@ -68,31 +68,33 @@ export function searchdata(term, type) { // Searches users and posts for any mat
return search_results;
};
export function getdata(data, index=-1) {
if (config["data_storage"] == "json") {
if (data == "posts" || data == 'users' || data == 'comments') {
let result = func.require_module(`../data/${data}.json`)
if (index != -1) {
if (index < result.length) {
return result[index]
}
return 1 // This index doesn't exist
export function getdata(data_type, key=-1, value=-1) {
let result = undefined
switch (config["data_storage"]) {
case 'json':
switch (data_type) {
case 'users':
case 'posts':
case 'comments':
result = func.require_module(`../data/${data_type}.json`)
if (key != -1) {
return result[func.find_key_value_pair(result, key, value)]
return -1 // This index doesn't exist
}
return result
}
else if (data == "hitcount") {
let result = func.require_module('../data/data.json') // This file is actually called data.json
break;
case 'hitcount':
result = func.require_module('../data/data.json') // This file is actually called data.json
return result["hitcount"]
}
else {
break;
default:
console.log("Error, invalid requested")
return 1
return -1
break;
}
}
break;
// NOT YET WORKING!
if (config["data_storage"] == "mysql") {
case 'mysql':
const mysql = require('mysql');
let con = mysql.createConnection({
host: config.database.host,

View File

@@ -7,12 +7,15 @@ const locale = require(`../locales/${config.locale}.json`)
// This function requires a module without caching it
// So the server doesn't need to be restarted, though this can slow it down a bit.
// https://stackoverflow.com/a/16060619
export function require_module(module) {
if (config.cache_data == false) {
export function require_module(module)
{
if (config.cache_data == false)
{
delete require.cache[require.resolve(module)];
return require(module);
}
else {
else
{
return require(module);
}
}
@@ -22,7 +25,8 @@ export function require_module(module) {
// this converts unix time (an integer) into a string that is formatted according to config.js
// uses date-fns's fromUnixTime() and format() functions
// returns the formatted date (string)
export function unix_time_to_date_format(unix_time) {
export function unix_time_to_date_format(unix_time)
{
const { fromUnixTime, format, getUnixTime } = require("date-fns") // A date utility library
let date = fromUnixTime(unix_time)
let formatted_date = format(date, config.date_format)
@@ -33,14 +37,16 @@ export function unix_time_to_date_format(unix_time) {
// eg "Mon, 23 May 2025 18:59:59 +0100"
// accepts unix time (int)
// returns the formatted date (string)
export function unix_time_to_rss_date(unix_time) {
export function unix_time_to_rss_date(unix_time)
{
const { fromUnixTime, format, getUnixTime } = require("date-fns") // A date utility library
let date = fromUnixTime(unix_time)
let formatted_date = format(date, "EEE, dd MMM yyyy HH:mm:ss")
return `${formatted_date} ${config.time_zone}`
}
// And again with atom's date format
export function unix_time_to_atom_date(unix_time) {
export function unix_time_to_atom_date(unix_time)
{
const { fromUnixTime, format, getUnixTime } = require("date-fns") // A date utility library
let date = fromUnixTime(unix_time)
let formatted_date = format(date, "yyyy-MM-dd'T'HH:mm:ss'Z'")
@@ -51,13 +57,17 @@ export function unix_time_to_atom_date(unix_time) {
// 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
export function render_tags(tags) {
export function render_tags(tags)
{
let string = "" // Initialises the string
if (tags.length == 1 && tags[0] == "") {
if (tags.length == 1 && tags[0] == "")
{
string = ''; // If there are no tags, output nothing
}
else {
for (let tag_index = 0; tag_index < tags.length; tag_index++) { // Loop over each tag
else
{
for (let tag_index = 0; tag_index < tags.length; tag_index++)
{ // Loop over each tag
string += `<a href="/tag/${tags[tag_index].trim()}">#${tags[tag_index].trim()}</a> ` // Adds the tag to the string as a HTML href
}
}
@@ -68,10 +78,13 @@ export function render_tags(tags) {
// 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
export function get_userID(username) {
const users = require("../data/users.json")
for (let i = 0; i < users.length; i++) { // Loop over every user
if (users[i]['username'] == username) {
export function get_userID(username)
{
const users = require_module("../data/users.json")
for (let i = 0; i < users.length; i++)
{ // Loop over every user
if (users[i]['username'] == username)
{
return i // If the username matches then return the index of that user
}
}
@@ -82,7 +95,8 @@ export function get_userID(username) {
// https://www.freeformatter.com/html-entities.html
// accepts a string
// returns a string with some character replaced by their entities
export function escape_input(input) {
export function escape_input(input)
{
let output = input
.replaceAll("&", "&amp;") // This must be first
.replaceAll("<", "&lt;")
@@ -97,7 +111,8 @@ export function escape_input(input) {
// Render comment content by replacing the >> int with a url link to that comment
// Syntax: ">> postID-commentID"
export function render_comment(comment_content) {
export function render_comment(comment_content)
{
return comment_content
.replaceAll(/>> ([0-9]*)-([0-9]*)/g, "<a href='/comment/$1-$2'>>> $1-$2</a>")
.replaceAll(/>>([0-9]*)-([0-9]*)/g, "<a href='/comment/$1-$2'>>>$1-$2</a>")
@@ -108,9 +123,11 @@ export function render_comment(comment_content) {
};
// Renders a string into markdown using markdown-it library
export function render_md(content) {
export function render_md(content)
{
const markdownit = require("markdown-it")
const md = markdownit({ // this is just defining some options for markdown-it, should I add this to config.json?
const md = markdownit
({ // this is just defining some options for markdown-it, should I add this to config.json?
html: false,
xhtmlOut: false,
breaks: true,
@@ -121,3 +138,11 @@ export function render_md(content) {
return md.render(content)
};
export function find_key_value_pair(data_array, key, value) {
for (let i = 0; i < data_array.length; i++) {
if (data_array[i][key] == value) {
return i
}
}
return -1
};

View File

@@ -31,11 +31,10 @@ router.post("/submit_comment", (req,res) => {
new_comment = {
"name": name,
"content": content,
"id": comments[postID].length,
"id": comments[postID]['comments'].length,
"pubdate": unix_timestamp,
"postID": postID,
};
comments[postID].push(new_comment);
comments[postID]['comments'].push(new_comment);
fs.writeFileSync(`../data/comments.json`, `${JSON.stringify(comments)}`, 'utf-8');
}
@@ -59,8 +58,9 @@ router.post("/submit_post", (req,res) => {
else if (users[func.get_userID(username)]['hash'] == password) { // Password matches
console.log(username, "is submitting a post titled:", title);
id = posts.length
posts.push({
"id": posts.length,
"id": id,
"userID": func.get_userID(username),
"title": title,
"content": content,
@@ -69,7 +69,7 @@ router.post("/submit_post", (req,res) => {
"tags": tags,
})
fs.writeFileSync(`../data/posts.json`, `${JSON.stringify(posts)}`, 'utf-8');
comments.push([])
comments.push({'id': id, 'comments': []})
fs.writeFileSync(`../data/comments.json`, `${JSON.stringify(comments)}`)
res.redirect(302, "/");
}
@@ -216,7 +216,7 @@ router.get('/search', (req, res) => {
console.log('searching for: ', search_term);
const search_results = data.searchdata(search_term, search_type); // data.searchdata returns an array of search results
res.render('partials/search', {
res.render('pages/search', {
config,
locale,
search_results,

View File

@@ -13,7 +13,7 @@ router.get("/index/pages", (req,res) => {
users: data.getdata('users'),
comments: data.getdata('comments'),
});
}); // /index/posts
}); // /index/pages
router.get("/index/posts", (req,res) => {
res.render("indexes/posts", {
config,
@@ -25,13 +25,13 @@ router.get("/index/users", (req,res) => {
config,
users: data.getdata('users'),
});
}); // /index/posts
}); // /index/users
router.get("/index/comments", (req,res) => {
res.render("indexes/comments", {
config,
comments: data.getdata('comments'),
});
}); // /index/posts
}); // /index/comments
module.exports = router;

View File

@@ -33,7 +33,7 @@ router.get("/", (req,res) => {
// Users
router.get("/user/:username", (req, res) => {
const userID = func.get_userID(req.params.username)
let user = data.getdata('users', userID)
let user = data.getdata('users', 'id', userID)
if (userID != -1) {
res.render("pages/user",
{
@@ -61,7 +61,7 @@ router.get("/user/:username", (req, res) => {
// Posts
router.get("/post/:post_index", (req, res) => {
const postID = parseInt(req.params.post_index)
let post = data.getdata('posts', postID)
let post = data.getdata('posts','id', postID)
if (post == 1) { // data.getdata returns error code 1 if nothing is available
res.render("partials/message", {
message: locale.post_doesnt_exist,
@@ -78,8 +78,8 @@ router.get("/post/:post_index", (req, res) => {
locale,
post,
postID,
user: data.getdata('users', post.userID),
comments: data.getdata('comments', postID),
user: data.getdata('users','id', post.userID),
comments: data.getdata('comments','id', postID)["comments"],
fromUnixTime,
format,
getUnixTime,
@@ -117,7 +117,7 @@ router.get("/comment/:postID-:commentID", (req,res) => {
const commentID = parseInt(req.params.commentID);
const postID = parseInt(req.params.postID);
let posts_comments = data.getdata('comments', postID)
let posts_comments = data.getdata('comments', 'id', postID)["comments"]
let comment = 1
// For loop to find the comment with matching ID
posts_comments.forEach((current_comment, index) => {

View File

@@ -20,7 +20,7 @@
<% }; %>
Comments:<br/>
<% for (let postID = 0; postID < comments.length; postID++) { %>
<% for (let comment_index = 0; comment_index < comments[postID].length; comment_index++) { %>
<% for (let comment_index = 0; comment_index < comments[postID]['comments'].length; comment_index++) { %>
<a href="/comment/<%= postID %>-<%= comment_index %>"><%= postID %>-<%= comment_index %></a><br/>
<% }; %>
<% }; %>

View File

@@ -5,7 +5,7 @@
</head>
<body>
<% for (let postID = 0; postID < comments.length; postID++) { %>
<% for (let comment_index = 0; comment_index < comments[postID].length; comment_index++) { %>
<% for (let comment_index = 0; comment_index < comments[postID]['comments'].length; comment_index++) { %>
<a href="/comment/<%= postID %>-<%= comment_index %>"><%= postID %>-<%= comment_index %></a><br/>
<% }; %>
<% }; %>

View File

@@ -1,37 +0,0 @@
<!DOCTYPE html>
<html lang='<%- config.locale %>'>
<head>
<%- include('../partials/head'); %>
</head>
<body>
<div id='header'>
<%- include('../headers/site_wide'); %>
</div>
<div id='advanced-search'>
<form method="GET" action="/search">
<label>Search Term:</label>
<input type='text' placeholder='🔍' name='q' value='<%- search_term %>'><br/>
<label>Search for:</label><br/>
<label>Post:</label>
<input type="checkbox" name="type" value="post" <% if (search_type.includes('post')) {%>checked<% } %>><br/>
<label>User:</label>
<input type="checkbox" name="type" value="user" <% if (search_type.includes('user')) {%>checked<% } %>><br/>
<input type="submit" value="Submit">
</form>
</div>
<%- config.seperator %>
<div id='results'>
<% search_results.posts.forEach((result, index) => { %>
<a href="/post/<%- result.id %>"><%- result.title %></a><br/>
<% }); %>
<% search_results.users.forEach((result, index) => { %>
<a href="/user/<%- result.username %>"><%- result.prettyname %></a><br/>
<% }); %>
</div>
</body>
</html>

View File

@@ -15,7 +15,7 @@
</div>
<div id="post-details">
<span id="post-author">
<i><%= locale.written_by %> <a href="/user/<%= user.username %>"><%= user.username %></a></i>
<i><%= locale.written_by %> <a href="/user/<%= user.username %>"><%= user.prettyname %></a></i>
</span>
-
<span id="post-pubdate">

View File

@@ -15,7 +15,7 @@
</div>
<div id="post-details">
<span id="post-author">
<i><a href="/user/<%= user.username %>"><%= user.username %></a></i>
<i><a href="/user/<%= user.username %>"><%= user.prettyname %></a></i>
</span>
-
<span id="post-pubdate">

View File

@@ -15,7 +15,7 @@
</div>
<div id="post-details">
<span id="post-author">
<i><a href="/user/<%= user.username %>"><%= user.username %></a></i>
<i><a href="/user/<%= user.username %>"><%= user.prettyname %></a></i>
</span>
-
<span id="post-pubdate">

View File

@@ -15,7 +15,7 @@
</div>
<div id="post-details">
<span id="post-author">
<i><a href="/user/<%= user.username %>"><%= user.username %></a></i>
<i><a href="/user/<%= user.username %>"><%= user.prettyname %></a></i>
</span>
-
<span id="post-pubdate">

View File

@@ -15,11 +15,23 @@ body {
input, textarea, button {
border: none;
border-radius: 5px;
font-size: 20px;
}
textarea {
width: 100%;
height: 250px;
field-sizing: content; /* Only supported by Chromium */
}
a {
text-decoration: none;
}
#search-form input {
border: none;
border-radius: 0px;
font-size: 14px;
}
}
a:hover {
text-decoration: underline;
}