From 7bafb670bf9341a308372665463d4d23df97fbe0 Mon Sep 17 00:00:00 2001 From: fatchan Date: Mon, 1 Apr 2019 16:34:26 +0000 Subject: [PATCH] per-thread user IDs AND preview post truncation to 16 line and 1000 chars. --- controllers/api.js | 11 +++++++++-- models/api/make-post.js | 20 +++++++++++++++++--- static/css/style.css | 24 ++++++++++++++++++++---- views/includes/postform.pug | 2 +- views/mixins/post.pug | 22 ++++++++++++++++++++-- views/pages/board.pug | 9 +++++---- views/pages/thread.pug | 5 +++-- 7 files changed, 75 insertions(+), 18 deletions(-) diff --git a/controllers/api.js b/controllers/api.js index 4b0f3f5b..24a7dd39 100644 --- a/controllers/api.js +++ b/controllers/api.js @@ -13,14 +13,21 @@ const express = require('express') /* (async () => { + await Boards.deleteIncrement('pol'); await Boards.deleteIncrement('b'); + await Posts.deleteAll('pol'); + await Posts.deleteAll('b'); await Boards.deleteAll(); + await Boards.insertOne({ + _id: 'pol', + name: 'Politically Incorrect', + description: 'Political posts go here.', + }) await Boards.insertOne({ _id: 'b', - name: 'random', + name: 'Random', description: 'post anything here', }) - await Posts.deleteAll('b'); })(); */ diff --git a/models/api/make-post.js b/models/api/make-post.js index 4f3fb0cc..3a2ecc66 100644 --- a/models/api/make-post.js +++ b/models/api/make-post.js @@ -2,6 +2,9 @@ const uuidv4 = require('uuid/v4') , path = require('path') + , util = require('util') + , crypto = require('crypto') + , randomBytes = util.promisify(crypto.randomBytes) , uploadDirectory = require(__dirname+'/../../helpers/uploadDirectory.js') , Posts = require(__dirname+'/../../db-models/posts.js') , fileUpload = require(__dirname+'/../../helpers/files/file-upload.js') @@ -12,17 +15,19 @@ const uuidv4 = require('uuid/v4') module.exports = async (req, res, numFiles) => { // check if this is responding to an existing thread + let salt; if (req.body.thread) { let thread; try { - thread = await Posts.getThread(req.params.board, req.body.thread); + thread = await Posts.getPost(req.params.board, req.body.thread); } catch (err) { console.error(err); return res.status(500).json({ 'message': 'Error fetching from DB' }); } - if (!thread) { + if (!thread || thread.thread != null) { return res.status(400).json({ 'message': 'thread does not exist' }) } + salt = thread.salt; } let files = []; @@ -71,6 +76,10 @@ module.exports = async (req, res, numFiles) => { } } + if (!salt) { + salt = (await randomBytes(128)).toString('hex'); + } + const data = { 'name': req.body.name || 'Anonymous', 'subject': req.body.subject || '', @@ -78,9 +87,14 @@ module.exports = async (req, res, numFiles) => { 'message': req.body.message || '', 'thread': req.body.thread || null, 'password': req.body.password || '', - 'files': files + 'files': files, + 'salt': !req.body.thread ? salt : '', }; + const ip = req.headers['x-real-ip'] || req.connection.remoteAddress; + + data.userId = crypto.createHash('sha256').update(salt + ip + req.params.board).digest('hex').substring(0, 6); + const post = await Posts.insertOne(req.params.board, data) const redirect = '/' + req.params.board + '/thread/' + (req.body.thread || post.insertedId); diff --git a/static/css/style.css b/static/css/style.css index ac2e954b..873ac110 100644 --- a/static/css/style.css +++ b/static/css/style.css @@ -9,6 +9,10 @@ body { margin: 0; } +blockquote { + word-break: break-all; +} + span { margin-right: 5px; } @@ -24,13 +28,21 @@ input, textarea { font-size: 10pt; border-radius: 3px; max-width:100%; + border: none; + margin: 2px; + padding: 5px; } -.form-post-wrapper { +.form-wrapper { align-items: center; margin: 10px 0; } +.delete-wrapper { + align-items: center; + flex-direction: row; +} + .form-post { display: flex; flex-direction: column; @@ -129,7 +141,7 @@ input textarea { } .navbar { - border-bottom: 1px solid gray; + border-bottom: 1px solid lightgray; margin: 0; position: fixed; width: 100%; @@ -151,14 +163,14 @@ input textarea { } .footer { - border-top: 1px solid gray; + border-top: 1px solid lightgray; text-align: center; flex-shrink: 0; margin-top: auto; } table, th, td { - border-bottom: 1px solid gray; + border-bottom: 1px solid lightgray; border-collapse: collapse; } @@ -175,6 +187,10 @@ th, td { padding: 5px; } +hr { + color: lightgray; +} + @media only screen and (max-width: 800px) { input { diff --git a/views/includes/postform.pug b/views/includes/postform.pug index 425d84dd..1e98c22d 100644 --- a/views/includes/postform.pug +++ b/views/includes/postform.pug @@ -1,4 +1,4 @@ -section.form-post-wrapper +section.form-wrapper form.form-post(action='/api/board/'+board._id, enctype='multipart/form-data', method='POST') input(type='hidden' name='_csrf' value=csrf) diff --git a/views/mixins/post.pug b/views/mixins/post.pug index 6219202b..36b0fad0 100644 --- a/views/mixins/post.pug +++ b/views/mixins/post.pug @@ -1,4 +1,4 @@ -mixin post(board, post) +mixin post(board, post, truncate) article(class='post-container '+(post.thread ? '' : 'op')) header.post-info input.post-check(type='checkbox', name='checked[]' value=post._id) @@ -6,6 +6,7 @@ mixin post(board, post) span.post-subject #{post.subject} span.post-name #{post.name} span #{post.date.toLocaleString()} + span.user-id(style=`background: #${post.userId}`) #{post.userId} if post.thread == null span: a(href=`/${board._id}/thread/${post._id}`) ##{post._id} else @@ -22,5 +23,22 @@ mixin post(board, post) a(target='_blank' href='/img/'+file.filename) object(data='/img/thumb-'+file.filename type=file.mimetype) if post.message - blockquote.post-message(style='white-space: pre-wrap;') #{post.message} + if truncate + - + const splitPost = post.message.split('\n'); + const messageLines = splitPost.length; + const postLength = post.message.length; + let truncatedMessage = post.mesage; + let truncated = false; + if (messageLines > 16 || post.message.length > 1000) { + truncatedMessage = splitPost.slice(0, 16).join('\n').substring(0, 1000); + truncated = true; + } + if truncated + blockquote.post-message(style='white-space: pre-wrap;') #{truncatedMessage} + p Message too long. #[a(href=`/${board._id}/thread/${post.thread == null ? post._id : post.thread}#${post._id}`) Click here] to view the full text. + else + blockquote.post-message(style='white-space: pre-wrap;') #{post.message} + else + blockquote.post-message(style='white-space: pre-wrap;') #{post.message} diff --git a/views/pages/board.pug b/views/pages/board.pug index 18fd08f1..1d98f6ba 100644 --- a/views/pages/board.pug +++ b/views/pages/board.pug @@ -16,9 +16,10 @@ block content hr(size=1) for thread in threads section.thread(id=thread._id) - +post(board, thread) + +post(board, thread, true) for post in thread.replies - +post(board, post) + +post(board, post, true) hr(size=1) - input#password(type='password', name='password', placeholder='password (for deletion)' autocomplete='off') - input(type='submit', value='delete') + section.delete-wrapper + input#password(type='password', name='password', placeholder='password (for deletion)' autocomplete='off') + input(type='submit', value='delete') diff --git a/views/pages/thread.pug b/views/pages/thread.pug index 7fbfc480..eca58378 100644 --- a/views/pages/thread.pug +++ b/views/pages/thread.pug @@ -21,8 +21,9 @@ block content for post in thread.replies +post(board, post) hr(size=1) - input#password(type='password', name='password', placeholder='password (for deletion)' autocomplete='off') - input(type='submit', value='delete') + section.delete-wrapper + input#password(type='password', name='password', placeholder='password (for deletion)' autocomplete='off') + input(type='submit', value='delete')