From a313426e2acbccb6fad74f1d8ab42b86de0c37cd Mon Sep 17 00:00:00 2001 From: fatchan Date: Wed, 27 Mar 2019 15:33:33 +0000 Subject: [PATCH] good enough styling for now --- controllers/api.js | 96 ++++++++++++++++++++++++++----------- controllers/frontend.js | 6 +-- models/boards.js | 41 ++++++++++++++++ models/posts.js | 16 +++++-- static/css/style.css | 35 ++++++++++++-- views/includes/footer.pug | 2 +- views/includes/navbar.pug | 6 +-- views/includes/postform.pug | 16 +++++++ views/mixins/post.pug | 11 +++-- views/pages/board.pug | 2 + views/pages/thread.pug | 3 +- 11 files changed, 185 insertions(+), 49 deletions(-) create mode 100644 views/includes/postform.pug diff --git a/controllers/api.js b/controllers/api.js index bef3b35f..9c5a6866 100644 --- a/controllers/api.js +++ b/controllers/api.js @@ -3,33 +3,73 @@ const express = require('express') , router = express.Router() , utils = require('../utils.js') + , { check, validationResult } = require('express-validator/check') , Posts = require(__dirname+'/../models/posts.js') , Boards = require(__dirname+'/../models/boards.js'); /* roughly: - - GET /api/board/:board/catalog -> all threads (catalog) - - GET /api/board/:board/recent/:page? -> recent posts per page (board homepage) - - GET /api/board/:board/thread/:thread -> get all posts in a thread + - GET /board/:board/catalog -> all threads (catalog) + - GET /board/:board/recent/:page? -> recent posts per page (board homepage) + - GET /board/:board/thread/:thread -> get all posts in a thread - - POST /api/board/:board -> make a new thread - - POST /api/board/:board/thread/:thread -> make a new post in a thread + - POST /board/:board -> make a new thread + - POST /board/:board/thread/:thread -> make a new post in a thread - - DELETE /api/board/:board/post/:id -> delete a post + - DELETE /board/:board/post/:id -> delete a post */ // make new post -router.post('/api/board/:board', Boards.exists, async (req, res, next) => { +router.post('/board/:board', Boards.exists, [ + check('author').optional(), + check('subject').optional(), + check('thread').optional(), + check('content').not().isEmpty().withMessage('missing message content'), +], async (req, res, next) => { + + //return array of errors about bad post + const errors = validationResult(req) + if (!errors.isEmpty()) { + return res.json({errors:errors.array()}) + } + + //ghetto setting to 0 so expres validator doesnt skip null value. needs looking into. + if (req.body.thread) { + let thread; + try { + thread = await Posts.getThread(req.params.board, req.body.thread); + } catch (err) { + return res.status(500).json({ 'message': 'Error fetching from DB' }); + } + if (!thread) { + return res.status(400).json({ 'message': 'thread does not exist' }) + } + } + + //TODO: handle file uploads instead of just doing nothing + + //add the post + const post = await Posts.insertOne(req.params.board, { + 'author': req.body.author || 'Anonymous', + 'subject': req.body.subject || '', + 'date': new Date(), + 'content': req.body.content, + 'thread': req.body.thread || null + }) + + const redirect = '/' + req.params.board + '/thread/' + (req.body.thread || post.insertedId); + + return res.redirect(redirect) }); // delete a post -router.delete('/api/board/:board/post/:id', Boards.exists, async (req, res, next) => { +router.delete('/board/:board/post/:id(\\d+)', Boards.exists, async (req, res, next) => { }); // get recent threads and preview posts -router.get('/api/board/:board/recent/:page', Boards.exists, async (req, res, next) => { +router.get('/board/:board/recent/:page(\\d+)?', Boards.exists, async (req, res, next) => { //get the recently bumped thread & preview posts let threads; @@ -48,12 +88,12 @@ router.get('/api/board/:board/recent/:page', Boards.exists, async (req, res, nex }); // get a thread -router.get('/api/board/:board/thread/:thread([a-f\d]{24})', Boards.exists, async (req, res, next) => { +router.get('/board/:board/thread/:id(\\d+)', Boards.exists, async (req, res, next) => { //get the recently bumped thread & preview posts let thread; try { - thread = await Posts.getThread(req.params.board, req.params.thread); + thread = await Posts.getThread(req.params.board, req.params.id); } catch (err) { return res.status(500).json({ 'message': 'Error fetching from DB' }); } @@ -67,7 +107,7 @@ router.get('/api/board/:board/thread/:thread([a-f\d]{24})', Boards.exists, async }); // get array of threads (catalog) -router.get('/api/board/:board/catalog', Boards.exists, async (req, res, next) => { +router.get('/board/:board/catalog', Boards.exists, async (req, res, next) => { //get the recently bumped thread & preview posts let data; @@ -86,23 +126,24 @@ router.get('/api/board/:board/catalog', Boards.exists, async (req, res, next) => }); //get list of boards -router.get('/api/boards', Boards.exists, async (req, res, next) => { +router.get('/boards', Boards.exists, async (req, res, next) => { - //get a list of boards - let boards; - try { - boards = await Boards.find(); - } catch (err) { + //get a list of boards + let boards; + try { + boards = await Boards.find(); + } catch (err) { return res.status(500).json({ 'message': 'Error fetching from DB' }) - } + } - //render the page - res.json(boards) + //render the page + res.json(boards) }); - +/* (async () => { + await Boards.deleteIncrement('b'); await Boards.deleteAll(); await Boards.insertOne({ _id: 'b', @@ -110,26 +151,27 @@ router.get('/api/boards', Boards.exists, async (req, res, next) => { description: 'post anything here', }) await Posts.deleteAll('b'); - for (let i = 0; i < 5; i++) { + for (let i = 0; i < 3; i++) { const thread = await Posts.insertOne('b', { 'author': 'Anonymous', - 'title': 'post title', + 'subject': 'subject', 'date': new Date(), 'content': Math.random().toString(36).replace(/[^a-z]+/g, ''), 'thread': null }) - for (let j = 0; j < 30; j++) { + for (let j = 0; j < 5; j++) { await new Promise(resolve => {setTimeout(resolve, 500)}) const post = await Posts.insertOne('b', { 'author': 'Anonymous', - 'title': 'post title', + 'subject': 'subject', 'date': new Date(), 'content': Math.random().toString(36).replace(/[^a-z]+/g, ''), - 'thread': thread.insertedId + 'thread': thread.insertedId + '' }) } } })(); +*/ module.exports = router; diff --git a/controllers/frontend.js b/controllers/frontend.js index 9d5eb310..7bdec24e 100644 --- a/controllers/frontend.js +++ b/controllers/frontend.js @@ -19,7 +19,7 @@ roughly: */ // board page/recents -router.get('/:board/:page?', Boards.exists, async (req, res, next) => { +router.get('/:board/:page(\\d+)?', Boards.exists, async (req, res, next) => { //get the recently bumped thread & preview posts let threads; @@ -38,12 +38,12 @@ router.get('/:board/:page?', Boards.exists, async (req, res, next) => { }); // thread view page -router.get('/:board/thread/:thread([a-f\\d]{24})', Boards.exists, async (req, res, next) => { +router.get('/:board/thread/:id(\\d+)', Boards.exists, async (req, res, next) => { //get the recently bumped thread & preview posts let thread; try { - thread = await Posts.getThread(req.params.board, req.params.thread); + thread = await Posts.getThread(req.params.board, req.params.id); } catch (err) { return next(err); } diff --git a/models/boards.js b/models/boards.js index 240068e8..209b61bc 100644 --- a/models/boards.js +++ b/models/boards.js @@ -42,4 +42,45 @@ module.exports = { }, + getNextId: async (board) => { + + const increment = await db.collection('counters').findOneAndUpdate( + { + '_id': board + }, + { + '$inc': { + 'sequence_value': 1 + } + }, + { + 'upsert': true + } + ); + + // faster than toString() + return increment.value.sequence_value + ''; + + }, + + deleteIncrement: async (board) => { + + await db.collection('counters').findOneAndUpdate( + { + '_id': board + }, + { + '$set': { + 'sequence_value': 1 + } + }, + { + 'upsert': true + } + ); + + return; + + }, + } diff --git a/models/posts.js b/models/posts.js index dc2be17d..7f0002d3 100644 --- a/models/posts.js +++ b/models/posts.js @@ -1,6 +1,7 @@ 'use strict'; const Mongo = require(__dirname+'/../helpers/db.js') + , Boards = require(__dirname+'/boards.js') , db = Mongo.client.db('posts'); module.exports = { @@ -36,10 +37,10 @@ module.exports = { // get thread post and potential replies concurrently const data = await Promise.all([ db.collection(board).findOne({ - '_id': Mongo.ObjectId(id) + '_id': id }), db.collection(board).find({ - 'thread': Mongo.ObjectId(id) + 'thread': id }).sort({ '_id': 1 }).toArray() @@ -68,7 +69,7 @@ module.exports = { // get a post return db.collection(board).findOne({ - '_id': Mongo.ObjectId(id) + '_id': id }); }, @@ -80,12 +81,19 @@ module.exports = { await db.collection(board).updateOne({ '_id': data.thread }, { - $set: { + '$set': { 'bumped': Date.now() } }) } + data._id = await Boards.getNextId(board); + + //this is an OP, so set the bump date so its pushed to the top + if (data.thread == null) { + data.bumped = Date.now() + } + return db.collection(board).insertOne(data); }, diff --git a/static/css/style.css b/static/css/style.css index 376b9453..8e44dd3b 100644 --- a/static/css/style.css +++ b/static/css/style.css @@ -9,8 +9,20 @@ body { margin: 0; } +input, textarea { + display: block; + font-family: arial, helvetica, sans-serif; + font-size: 10pt; + border-radius: 3px; +} + +input textares { + padding: 8px; +} + .container { margin: 5px; + margin-top: 57px; } .board-title { @@ -22,6 +34,7 @@ body { } .post-container { + margin-top: 5px; margin-left: 15px; padding: 5px; background: #D6DAF0; @@ -35,17 +48,29 @@ body { .navbar { border-bottom: 1px solid black; margin: 0; - padding: 5px; + line-height: 50px; + height: 50px; + position: fixed; + width: 100%; + background: #eef2ff; } .nav-item { - list-style: none; - display: inline; - padding-left: 20px; - line-height: 50px; + font-size: 14pt; + text-decoration: none; + float: left; + background: #D6DAF0; + padding-left: 10px; + padding-right: 10px; +} + +.nav-item:hover { + box-shadow: inset 0 0 100px 100px rgba(255,255,255,.1); } .footer { + line-height: 50px; + border-top: 1px solid black; text-align: center; flex-shrink: 0; margin-top: auto; diff --git a/views/includes/footer.pug b/views/includes/footer.pug index 66c44243..b2009ff1 100644 --- a/views/includes/footer.pug +++ b/views/includes/footer.pug @@ -1,2 +1,2 @@ .footer - p footer + p not lynxchan ™ diff --git a/views/includes/navbar.pug b/views/includes/navbar.pug index 5e70db14..339382d0 100644 --- a/views/includes/navbar.pug +++ b/views/includes/navbar.pug @@ -1,3 +1,3 @@ -ul.navbar - li.nav-item: a(href='/') Home - li.nav-item: a(href='/login') Mod Login +.navbar + a.nav-item(href='/') Home + a.nav-item(href='/login') Mod Login diff --git a/views/includes/postform.pug b/views/includes/postform.pug new file mode 100644 index 00000000..f2cfc619 --- /dev/null +++ b/views/includes/postform.pug @@ -0,0 +1,16 @@ +p make a post: +form.form-post(action='/api/board/'+board._id, enctype='multipart/form-data', method='POST') + + input(type='hidden' name='_csrf' value=csrf) + + input(type='hidden' name='thread' value=thread != null ? thread._id : null) + + input#title(type='text', name='subject', placeholder='subject') + + input#name(type='text', name='author', placeholder='name') + + textarea#content(name='content', rows='8', cols='50', placeholder='message') + + input#file(type='file', name='files' multiple) + + input(type='submit', value='submit') diff --git a/views/mixins/post.pug b/views/mixins/post.pug index 2933823f..14643733 100644 --- a/views/mixins/post.pug +++ b/views/mixins/post.pug @@ -1,10 +1,11 @@ mixin post(board, post) div(class='post-container '+(post.thread ? '' : 'op')) - if post.thread == null - a(href=`/${board._id}/thread/${post._id}`) #{post._id} - else - a(href=`/${board._id}/thread/${post.thread}#${post._id}`) #{post._id} + span #{post.subject} span , #{post.author} span , #{post.date.toLocaleString()} - p #{post.title} + span , Post + if post.thread == null + a(href=`/${board._id}/thread/${post._id}`) ##{post._id} + else + a(href=`/${board._id}/thread/${post.thread}#${post._id}`) ##{post._id} p #{post.content} diff --git a/views/pages/board.pug b/views/pages/board.pug index 7e89b433..69544e8d 100644 --- a/views/pages/board.pug +++ b/views/pages/board.pug @@ -7,6 +7,8 @@ block head block content span #{board.name} - #{board.description} hr(size=1) + include ../includes/postform.pug + hr(size=1) for thread in threads +post(board, thread) for post in thread.replies diff --git a/views/pages/thread.pug b/views/pages/thread.pug index 07a780e7..4ce1c6c3 100644 --- a/views/pages/thread.pug +++ b/views/pages/thread.pug @@ -7,7 +7,8 @@ block head block content a(href='/'+board._id) Back to /#{board._id}/ hr(size=1) + include ../includes/postform.pug + hr(size=1) +post(board, thread) for post in thread.replies +post(board, post) - hr(size=1)