diff --git a/config.example.json b/config.example.json index 5da6bc6..cb5f1ab 100644 --- a/config.example.json +++ b/config.example.json @@ -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" }, diff --git a/helpers/blog-helper.js b/helpers/blog-helper.js deleted file mode 100644 index 1d12366..0000000 --- a/helpers/blog-helper.js +++ /dev/null @@ -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 -}; diff --git a/models/blog-post.js b/models/blog-post.js new file mode 100644 index 0000000..3d1281d --- /dev/null +++ b/models/blog-post.js @@ -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 +}; \ No newline at end of file diff --git a/models/post-author.js b/models/post-author.js new file mode 100644 index 0000000..e3a5211 --- /dev/null +++ b/models/post-author.js @@ -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 +}; \ No newline at end of file diff --git a/routes/admin.js b/routes/admin.js index 6d2197e..91de6bf 100644 --- a/routes/admin.js +++ b/routes/admin.js @@ -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; diff --git a/routes/blog.js b/routes/blog.js index f6dff60..7575367 100644 --- a/routes/blog.js +++ b/routes/blog.js @@ -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 diff --git a/server.js b/server.js index 3a3d87b..0191331 100644 --- a/server.js +++ b/server.js @@ -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}`);