visitor table

This commit is contained in:
simio 2024-12-05 00:56:01 -03:00
parent 6def4fbd98
commit 5ab2b57e79
8 changed files with 152 additions and 23 deletions

View File

@ -5,13 +5,14 @@ const serveIndex = require('./src/utils/serve_index')
const {engine} = require('express-handlebars') const {engine} = require('express-handlebars')
const indexRouter = require('./src/router/indexRouter') const indexRouter = require('./src/router/indexRouter')
const { handlebars } = require('hbs') const { handlebars } = require('hbs')
const bodyParser = require('body-parser')
const publicPath = "/public" const publicPath = "/public"
const inUrlPath = "public" const inUrlPath = "public"
webserver.engine('.hbs', engine({extname: '.hbs', helpers: { webserver.engine('.hbs', engine({extname: '.hbs', helpers: {
ifDivisibleBy: function (index, divisor, options) { ifDivisibleBy: function (index, divisor, options) {
if (index % divisor === 0) { if ((index+1) % divisor === 0) {
return options.fn(this); return options.fn(this);
} }
}, },
@ -27,6 +28,10 @@ webserver.set('view engine', '.hbs');
webserver.use(publicPath, express.static(inUrlPath), serveIndex(inUrlPath, { webserver.use(publicPath, express.static(inUrlPath), serveIndex(inUrlPath, {
})) }))
webserver.use(bodyParser.urlencoded({extend: false}));
webserver.use(bodyParser.json());
webserver.listen(port, () => { webserver.listen(port, () => {
console.log(`Listening on port ${port}`) console.log(`Listening on port ${port}`)

48
package-lock.json generated
View File

@ -9,13 +9,18 @@
"version": "1.0.0", "version": "1.0.0",
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"body-parser": "^1.20.3",
"byte-size": "^9.0.0", "byte-size": "^9.0.0",
"csv": "^6.3.10", "csv": "^6.3.10",
"express": "^4.21.0", "express": "^4.21.0",
"express-handlebars": "^8.0.1", "express-handlebars": "^8.0.1",
"fs": "^0.0.1-security",
"hbs": "^4.2.0", "hbs": "^4.2.0",
"japanese-date-converter": "^2.0.0", "japanese-date-converter": "^2.0.0",
"serve-index": "^1.9.1" "serve-index": "^1.9.1"
},
"devDependencies": {
"@types/node": "^22.10.1"
} }
}, },
"node_modules/@isaacs/cliui": { "node_modules/@isaacs/cliui": {
@ -35,6 +40,16 @@
"node": ">=12" "node": ">=12"
} }
}, },
"node_modules/@types/node": {
"version": "22.10.1",
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.1.tgz",
"integrity": "sha512-qKgsUwfHZV2WCWLAnVP1JqnpE6Im6h3Y0+fYgMTasNQ7V++CBX5OT1as0g0f+OyubbFqhf6XVNIsmN4IIhEgGQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"undici-types": "~6.20.0"
}
},
"node_modules/accepts": { "node_modules/accepts": {
"version": "1.3.8", "version": "1.3.8",
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
@ -200,9 +215,9 @@
} }
}, },
"node_modules/cookie": { "node_modules/cookie": {
"version": "0.6.0", "version": "0.7.1",
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz",
"integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==",
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">= 0.6" "node": ">= 0.6"
@ -215,9 +230,9 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/cross-spawn": { "node_modules/cross-spawn": {
"version": "7.0.3", "version": "7.0.6",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
"integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"path-key": "^3.1.0", "path-key": "^3.1.0",
@ -370,9 +385,9 @@
} }
}, },
"node_modules/express": { "node_modules/express": {
"version": "4.21.0", "version": "4.21.1",
"resolved": "https://registry.npmjs.org/express/-/express-4.21.0.tgz", "resolved": "https://registry.npmjs.org/express/-/express-4.21.1.tgz",
"integrity": "sha512-VqcNGcj/Id5ZT1LZ/cfihi3ttTn+NJmkli2eZADigjq29qTlWi/hAQ43t/VLPq8+UX06FCEx3ByOYet6ZFblng==", "integrity": "sha512-YSFlK1Ee0/GC8QaO91tHcDxJiE/X4FbpAyQWkxAvG6AXCuR65YzK8ua6D9hvi/TzUfZMpc+BwuM1IPw8fmQBiQ==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"accepts": "~1.3.8", "accepts": "~1.3.8",
@ -380,7 +395,7 @@
"body-parser": "1.20.3", "body-parser": "1.20.3",
"content-disposition": "0.5.4", "content-disposition": "0.5.4",
"content-type": "~1.0.4", "content-type": "~1.0.4",
"cookie": "0.6.0", "cookie": "0.7.1",
"cookie-signature": "1.0.6", "cookie-signature": "1.0.6",
"debug": "2.6.9", "debug": "2.6.9",
"depd": "2.0.0", "depd": "2.0.0",
@ -504,6 +519,12 @@
"node": ">= 0.6" "node": ">= 0.6"
} }
}, },
"node_modules/fs": {
"version": "0.0.1-security",
"resolved": "https://registry.npmjs.org/fs/-/fs-0.0.1-security.tgz",
"integrity": "sha512-3XY9e1pP0CVEUCdj5BmfIZxRBTSDycnbqhIOGec9QYtmVH2fbLpj86CFWkrNOkt/Fvty4KZG5lTglL9j/gJ87w==",
"license": "ISC"
},
"node_modules/function-bind": { "node_modules/function-bind": {
"version": "1.1.2", "version": "1.1.2",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
@ -1352,6 +1373,13 @@
"node": ">=0.8.0" "node": ">=0.8.0"
} }
}, },
"node_modules/undici-types": {
"version": "6.20.0",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz",
"integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==",
"dev": true,
"license": "MIT"
},
"node_modules/unpipe": { "node_modules/unpipe": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",

View File

@ -10,12 +10,17 @@
"license": "ISC", "license": "ISC",
"description": "", "description": "",
"dependencies": { "dependencies": {
"body-parser": "^1.20.3",
"byte-size": "^9.0.0", "byte-size": "^9.0.0",
"csv": "^6.3.10", "csv": "^6.3.10",
"express": "^4.21.0", "express": "^4.21.0",
"express-handlebars": "^8.0.1", "express-handlebars": "^8.0.1",
"fs": "^0.0.1-security",
"hbs": "^4.2.0", "hbs": "^4.2.0",
"japanese-date-converter": "^2.0.0", "japanese-date-converter": "^2.0.0",
"serve-index": "^1.9.1" "serve-index": "^1.9.1"
},
"devDependencies": {
"@types/node": "^22.10.1"
} }
} }

View File

@ -51,3 +51,8 @@
.maotatsu > small::selection{ .maotatsu > small::selection{
background-color: var(--celeste); background-color: var(--celeste);
} }
.visitor_table > tbody > tr > td{
max-width: 160px;
overflow-x: scroll;
}

View File

@ -0,0 +1,17 @@
const { readCsv } = require("../../utils/csv")
const { dirname } = require('path');
const rootDir = dirname(require.main.filename);
module.exports = async (req, res) => {
try{
const commentsRead = (await readCsv(rootDir + '/public/dynamic/sync/comments.csv'))
const comments = commentsRead.slice(commentsRead.length-16, commentsRead.length).reverse()
return {
comments
}
}
catch(err){
console.error(err)
res.send("Mistakes were made")
}
}

View File

@ -3,7 +3,7 @@ const express = require('express');
const router = express.Router(); const router = express.Router();
const { readCsv } = require('../utils/csv'); const { readCsv } = require('../utils/csv');
const { dirname } = require('path'); const { dirname } = require('path');
const appDir = dirname(require.main.filename); const thisDirectory = dirname(require.main.filename);
const fs = require('fs') const fs = require('fs')
function addPaths(path, renderParams = {}){ function addPaths(path, renderParams = {}){
@ -15,17 +15,17 @@ function addPaths(path, renderParams = {}){
const possibleHeader = 'headers/' + viewsRelativeDir.slice(0, -1) + '.hbs' const possibleHeader = 'headers/' + viewsRelativeDir.slice(0, -1) + '.hbs'
const possibleSettingsPath = '/src/router/common_path_settings/' + viewsRelativeDir.slice(0, -1) const possibleSettingsPath = '/src/router/common_path_settings/' + viewsRelativeDir.slice(0, -1)
if (fs.existsSync(appDir + possibleThemeStyle)){ if (fs.existsSync(thisDirectory + possibleThemeStyle)){
currentDefaultParams.theme = possibleThemeStyle currentDefaultParams.theme = possibleThemeStyle
} }
if (fs.existsSync(appDir + possibleHeaderStyle)){ if (fs.existsSync(thisDirectory + possibleHeaderStyle)){
currentDefaultParams.header_style = possibleHeaderStyle currentDefaultParams.header_style = possibleHeaderStyle
} }
if (fs.existsSync(appDir + '/views/partials/' + possibleHeader)){ if (fs.existsSync(thisDirectory + '/views/partials/' + possibleHeader)){
currentDefaultParams.headerPartial = possibleHeader.slice(0, -4) currentDefaultParams.headerPartial = possibleHeader.slice(0, -4)
} }
if (fs.existsSync(appDir + possibleSettingsPath + '/general.json')){ if (fs.existsSync(thisDirectory + possibleSettingsPath + '/general.json')){
const fileGeneralParams = JSON.parse(fs.readFileSync(appDir + possibleSettingsPath + '/general.json')) const fileGeneralParams = JSON.parse(fs.readFileSync(thisDirectory + possibleSettingsPath + '/general.json'))
currentDefaultParams = { currentDefaultParams = {
...currentDefaultParams, ...currentDefaultParams,
...fileGeneralParams ...fileGeneralParams
@ -53,7 +53,42 @@ router.get('/', (_req, res) => {
res.redirect('/public/pages/neocities-lyricaltokarev/index.html') res.redirect('/public/pages/neocities-lyricaltokarev/index.html')
}) })
addPaths(appDir + '/views/')
const recent_posters = []
router.post('/comment', (req, res) => {
const ip = req.header('x-forwarded-for') || req.connection.remoteAddress;
if(recent_posters.some( poster => poster.ip === ip)){
console.log("spammer, " + ip)
return res.redirect('/home#visitor_table')
}
recent_posters.push({
ip,
timeout: 3600
})
const comment = req.body.comment.replace(/"/g, '""');
fs.appendFileSync(thisDirectory + "/public/dynamic/sync/comments.csv", `\n${Date.now()},"${comment}",,1`)
res.redirect('/home#visitor_table')
})
setInterval(() => {
recent_posters.forEach(poster => {
poster.timeout -= 1
if (poster.timeout <= 0){
recent_posters.filter(p => {
return poster.ip !== p.ip
})
}
})
}, 1000)
addPaths(thisDirectory + '/views/')
module.exports = router; module.exports = router;

View File

@ -18,7 +18,6 @@
<li class="red"><strong>Content</strong></li> <li class="red"><strong>Content</strong></li>
<li class="red">Audience</li> <li class="red">Audience</li>
<li class="red"><strong>Consume</strong></li> <li class="red"><strong>Consume</strong></li>
<li class="red"><strong>Identity</strong></li>
<li>Policy</li> <li>Policy</li>
<li>Term</li> <li>Term</li>
<li>Deserve</li> <li>Deserve</li>
@ -34,9 +33,9 @@
<li class="red">Browse</li> <li class="red">Browse</li>
<li class="red"><strong>Develop</strong></li> <li class="red"><strong>Develop</strong></li>
<li class="red">Saturated</li> <li class="red">Saturated</li>
<li class="red"><strong>Bullying</strong></li>
<li>Right</li> <li>Right</li>
<li>Life</li> <li class="red">Life</li>
<li class="red">Tweet</li>
<li>Obscure</li> <li>Obscure</li>
<li>Vibe</li> <li>Vibe</li>
<li>Aesthetic</li> <li>Aesthetic</li>
@ -51,6 +50,7 @@
<li class="red">Yikes</li> <li class="red">Yikes</li>
<li class="red">Project</li> <li class="red">Project</li>
<li>Idea</li> <li>Idea</li>
<li class="red"><strong>Identity</strong></li>
<li class="red">Global</li> <li class="red">Global</li>
<li class="red">Emotional</li> <li class="red">Emotional</li>
<li>Planning</li> <li>Planning</li>
@ -72,6 +72,7 @@
<li class="red">Resource</li> <li class="red">Resource</li>
<li>Inequality</li> <li>Inequality</li>
<li>Fee</li> <li>Fee</li>
<li class="red"><strong>Bullying</strong></li>
<li>Equality</li> <li>Equality</li>
<li class="red">System</li> <li class="red">System</li>
<li>Design</li> <li>Design</li>
@ -90,6 +91,7 @@
<li class="red"><strong>Medium</strong></li> <li class="red"><strong>Medium</strong></li>
<li>Amount</li> <li>Amount</li>
<li class="red">Reader</li> <li class="red">Reader</li>
<li class="red">Dynamics</li>
<li class="red"><strong>Collective</strong></li> <li class="red"><strong>Collective</strong></li>
<li>Rational</li> <li>Rational</li>
<li class="red">Mental</li> <li class="red">Mental</li>
@ -107,6 +109,8 @@
<li class="red">Activism</li> <li class="red">Activism</li>
<li class="red"><strong>Activist</strong></li> <li class="red"><strong>Activist</strong></li>
<li class="red">Privacy</li> <li class="red">Privacy</li>
<li class="red"><strong>Cancel</strong></li>
<li class="red">Controversial</li>
<li>Subscribers</li> <li>Subscribers</li>
<li>Likes</li> <li>Likes</li>
<li class="red">Material</li> <li class="red">Material</li>
@ -143,6 +147,7 @@
<li><a href="#comicchat">Comic Chat</a></li> <li><a href="#comicchat">Comic Chat</a></li>
<li><a href="#yuugenmagan">YuugenMagan</a></li> <li><a href="#yuugenmagan">YuugenMagan</a></li>
<li><a href="#propaganda">Propaganda</a></li> <li><a href="#propaganda">Propaganda</a></li>
<li><a href="#visitor_table">Visitor Table</a></li>
<li><a href="#bottom">???</a></li> <li><a href="#bottom">???</a></li>
</ul> </ul>
</td> </td>
@ -262,7 +267,6 @@
<h2 id="yuugenmagan">YuugenMagan</h2> <h2 id="yuugenmagan">YuugenMagan</h2>
<img title="YuugenMagan" alt="YuugenMagan" src="/public/images/yuugenmagan.png"> <img title="YuugenMagan" alt="YuugenMagan" src="/public/images/yuugenmagan.png">
<p>YuugenMagan</p> <p>YuugenMagan</p>
<hr> <hr>
<p> <p>
<h2 id="propaganda">Propaganda</h2> <h2 id="propaganda">Propaganda</h2>
@ -286,10 +290,39 @@
<p>This site is an ip logger. Do not hotlink.</p> <p>This site is an ip logger. Do not hotlink.</p>
</p> </p>
<hr>
<h2 id="visitor_table">Visitor Table</h2>
<p>Experimental.</p>
<table width="100%" class="visitor_table" cellpadding="10" border="1">
<tbody>
<tr>
{{#each comments}}
<td valign="top">
{{{this.comment}}}
</td>
{{#ifDivisibleBy @index 4}}
</tr>
<tr>
{{/ifDivisibleBy}}
{{/each}}
</tr>
</tbody>
</table>
<br>
<div>
<form id="comment_form" method="post" action="/comment">
<textarea name="comment"></textarea>
<br>
<button type="submit">Submit</button>
</form>
</div>
<hr>
<audio controls> <audio controls>
<source src="https://mfiles.lyricaltokarev.com/1998%20-%20Shin%20Getter%20Robo%20-%20Sekai%20Saigo%20no%20Hi%20-%20Original%20Soundtrack%20Vol.%202/Shin%20Getter%20Robo%20-%20Vol.%202%20-%2022.%20HURRY%20UP%20DREAM%20%EF%BD%9ETabidachi%EF%BD%9E%20%28New%20Ending%20Theme%29.flac" type="audio/mpeg"> <source src="https://mfiles.lyricaltokarev.com/1998%20-%20Shin%20Getter%20Robo%20-%20Sekai%20Saigo%20no%20Hi%20-%20Original%20Soundtrack%20Vol.%202/Shin%20Getter%20Robo%20-%20Vol.%202%20-%2022.%20HURRY%20UP%20DREAM%20%EF%BD%9ETabidachi%EF%BD%9E%20%28New%20Ending%20Theme%29.flac" type="audio/mpeg">
</audio><br> </audio><br>
<hr>
{{>lyrics lyrics="<p> {{>lyrics lyrics="<p>
熱くなれ夢みた明日を<br> 熱くなれ夢みた明日を<br>
必ずいつかつかまえる<br> 必ずいつかつかまえる<br>

View File

@ -2,6 +2,7 @@
<main> <main>
<h2>2024</h2> <h2>2024</h2>
<ul> <ul>
<li>5/12 <a href="/home#visitor_table">This has to be a good idea...</a></li>
<li>4/12 <a href="/home">Lyrical Tokarev is now under martial rule!</a></li> <li>4/12 <a href="/home">Lyrical Tokarev is now under martial rule!</a></li>
<li>29/11 <a href="/home#navigation">Added a Navigation section.</a></li> <li>29/11 <a href="/home#navigation">Added a Navigation section.</a></li>
<li>27/11 <a href="/home#bottom">Did you see that shadow?</a></li> <li>27/11 <a href="/home#bottom">Did you see that shadow?</a></li>