updated blog-post functionality to use database + added admin api 404

This commit is contained in:
mrjvs 2018-10-13 17:53:08 +02:00
parent 1205b62d24
commit fc4a5b0063
7 changed files with 150 additions and 84 deletions

View File

@ -2,15 +2,6 @@
"http": {
"port": 8080
},
"blog": {
"authors": [
{
"name": "redducks",
"description": "passionate and violence loving programmer",
"image": "https://img00.deviantart.net/a0f8/i/2012/356/3/3/generic_anime_girl__1_by_light1523-d5ou547.png"
}
]
},
"database": {
"url": "mongodb://localhost:27017/pretendo_website"
},

View File

@ -1,59 +0,0 @@
/*
blog-helper.js -
blog post helper functionality
*/
// imports
const fs = require('fs');
const authors = require('../config.json').blog.authors;
const showdown = require('showdown');
const converter = new showdown.Converter({metadata: true});
function getAuthorByID(authorId) {
return authors[authorId];
}
function getBlogPostAsMarkdown(postId) {
try {
return fs.readFileSync(`posts/${postId}.md`);
} catch(exception) {
return null;
}
}
function getBlogPostAsHtml(postId) {
const markdown = getBlogPostAsMarkdown(postId);
if (!markdown) return;
return converter.makeHtml(markdown);
}
function getBlogPostExpressReady(postId) {
const markdown = getBlogPostAsMarkdown(postId);
if (!markdown) return;
const html = converter.makeHtml(markdown);
const metadata = converter.getMetadata();
const hbsObject = {
content: html,
date: metadata.releaseDate,
category: metadata.category,
author: getAuthorByID(metadata.authorId)
};
return hbsObject;
}
function writeMarkdownToFile(text) {
const length = fs.readdirSync('posts').length;
fs.writeFileSync(`posts/${length}.md`, text);
}
module.exports = {
getBlogPostAsHtml,
getBlogPostAsMarkdown,
getBlogPostExpressReady,
getAuthorByID,
writeMarkdownToFile
};

79
models/blog-post.js Normal file
View File

@ -0,0 +1,79 @@
/*
blog-post.js -
file containing the model file for a blog post
*/
// imports
const mongoose = require('mongoose');
const postAuthor = require('./post-author').postAuthorModel;
const showdown = require('showdown');
const converter = new showdown.Converter();
// admin user database layout
const blogPostSchema = new mongoose.Schema({
// html in content
content: {
type: String,
required: [true, 'Content is required.'],
trim: true
},
name: {
type: String,
required: [true, 'Name is required']
},
meta: {
urlTitle: {
type: String,
required: [true, 'Author is required'],
trim: true
},
author: {
type: String,
required: [true, 'Author is required'],
trim: true
},
date: {
type: Date,
default: Date.now
},
category: {
type: String,
required: [true, 'category is required'],
trim: true
}
}
});
blogPostSchema.methods.getContentAsHTML = function() {
return this.content;
};
blogPostSchema.methods.getBlogPostTemplateReady = function() {
return {
content: this.content,
title: this.name,
date: this.meta.date,
category: this.meta.category,
author: postAuthor.findById(this.meta.author).getPostAuthorTemplateReady()
};
};
blogPostSchema.statics.convertMarkdownToHtml = function(markdown) {
return converter.makeHtml(markdown);
};
blogPostSchema.statics.getPost = function(date, urlTitle, callback) {
return blogPostModel.findOne({
meta: {
date,
urlTitle
}
}, callback);
};
const blogPostModel = mongoose.model('blogPost', blogPostSchema);
module.exports = {
blogPostModel,
blogPostSchema
};

42
models/post-author.js Normal file
View File

@ -0,0 +1,42 @@
/*
blog-post.js -
file containing the model file for a blog post
*/
// imports
const mongoose = require('mongoose');
// post author database layout
const postAuthorSchema = new mongoose.Schema({
name: {
type: String,
required: [true, 'Name is required'],
trim: true
},
description: {
type: String,
required: [true, 'Description is required'],
trim: true
},
image: {
type: String,
trim: true
}
});
postAuthorSchema.methods.getPostAuthorTemplateReady = function() {
return {
authorName: this.name,
authorDescription: this.description,
authorProfilePicture: this.image
};
};
const postAuthorModel = mongoose.model('postAuthor', postAuthorSchema);
module.exports = {
postAuthorModel,
postAuthorSchema
};

View File

@ -123,5 +123,10 @@ router.get('/admin/api/v1/logout', adminUserMiddleware.adminAuthenticationRequir
common.sendApiReturn(res, {});
});
// configure api 404
router.use('/admin/api', (req, res) => {
common.sendApi404(res);
});
// export the router
module.exports = router;

View File

@ -7,25 +7,25 @@ file for handling routes regarding blog posts.
// imports
const router = require('express').Router();
const blogHelper = require('../helpers/blog-helper.js');
const common = require('../helpers/common');
const blogPostModel = require('../models/blog-post').blogPostModel;
// display blog post
router.get('/news/:id', async (req, res) => {
if (isNaN(req.params.id)) {
res.statusCode = 404;
res.render('404');
return;
router.get('/news/:date/:title', (req, res) => {
if (/[0-9]{2}-[0-9]{2}-[0-9]{4}/.test(req.params.date) && /([a-z]|[0-9]|-)+/.test(req.params.title.toLowerCase())) {
// params are correct format
blogPostModel.getPost(req.params.date, req.params.title.toLowerCase(), (err, post) => {
// error exists or no post exists with the date and name
if (err || !post) return common.sendDefault404(res);
// render blogpost
res.render('post', post.getBlogPostTemplateReady());
});
} else {
// params are incorrect
common.sendDefault404(res);
}
const hbsObject = blogHelper.getBlogPostExpressReady(req.params.id);
if (!hbsObject) {
res.statusCode = 404;
res.render('404');
return;
}
res.render('post', hbsObject);
});
// export router

View File

@ -72,6 +72,14 @@ app.use((req, res) => {
common.sendDefault404(res);
});
// TODO improve error handling
// TODO remove param decoding errors from logs example: "host/test/%"
// 4 parameters required to read the error, cant help the eslint error
app.use((err, req, res, next) => { // eslint-disable-line no-unused-vars
console.error(err.stack);
return res.status(500).send('Something broke!');
});
// startup
app.listen(config.http.port, () => {
console.log(`started the server on port: ${new String(config.http.port).green}`);