From fc4a5b00637e32dfd04de3ece098bbdf837cde79 Mon Sep 17 00:00:00 2001 From: mrjvs Date: Sat, 13 Oct 2018 17:53:08 +0200 Subject: [PATCH 01/13] updated blog-post functionality to use database + added admin api 404 --- config.example.json | 9 ----- helpers/blog-helper.js | 59 ------------------------------- models/blog-post.js | 79 ++++++++++++++++++++++++++++++++++++++++++ models/post-author.js | 42 ++++++++++++++++++++++ routes/admin.js | 5 +++ routes/blog.js | 32 ++++++++--------- server.js | 8 +++++ 7 files changed, 150 insertions(+), 84 deletions(-) delete mode 100644 helpers/blog-helper.js create mode 100644 models/blog-post.js create mode 100644 models/post-author.js 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}`); From 5c5772b76df403fb3c55892cbe081f73749cd75b Mon Sep 17 00:00:00 2001 From: mrjvs Date: Sat, 13 Oct 2018 23:11:53 +0200 Subject: [PATCH 02/13] blog post posting and reading finished. now just edit, sort and delete --- helpers/common.js | 10 ++++++++- models/blog-post.js | 18 +++++++++------- routes/admin.js | 51 +++++++++++++++++++++++++++++++++++++++++++++ routes/blog.js | 15 ++++++++----- views/admin.hbs | 15 +++++++++++++ views/post.hbs | 10 ++++----- 6 files changed, 100 insertions(+), 19 deletions(-) diff --git a/helpers/common.js b/helpers/common.js index 11f55f3..6143096 100644 --- a/helpers/common.js +++ b/helpers/common.js @@ -63,11 +63,19 @@ function sendApiError(res, code, errors) { }); } +// convert date to string +function convertDateToString(date) { + return date.getUTCFullYear() + '-' + + ('0' + (date.getUTCMonth()+1)).slice(-2) + '-' + + ('0' + date.getUTCDate()).slice(-2); +} + module.exports = { sendDefault404, sendApiReturn, sendApi404, sendApiGenericError, sendApiError, - sendApiAuthError + sendApiAuthError, + convertDateToString }; \ No newline at end of file diff --git a/models/blog-post.js b/models/blog-post.js index 3d1281d..642e5e8 100644 --- a/models/blog-post.js +++ b/models/blog-post.js @@ -7,9 +7,11 @@ file containing the model file for a blog post // imports const mongoose = require('mongoose'); -const postAuthor = require('./post-author').postAuthorModel; +const common = require('../helpers/common'); +//const postAuthor = require('./post-author').postAuthorModel; const showdown = require('showdown'); const converter = new showdown.Converter(); +converter.setFlavor('github'); // admin user database layout const blogPostSchema = new mongoose.Schema({ @@ -36,7 +38,9 @@ const blogPostSchema = new mongoose.Schema({ }, date: { type: Date, - default: Date.now + default: () => { + return new Date(common.convertDateToString(new Date())); + } }, category: { type: String, @@ -54,8 +58,8 @@ blogPostSchema.methods.getBlogPostTemplateReady = function() { content: this.content, title: this.name, date: this.meta.date, - category: this.meta.category, - author: postAuthor.findById(this.meta.author).getPostAuthorTemplateReady() + category: this.meta.category/*, + author: postAuthor.findById(this.meta.author).getPostAuthorTemplateReady()*/ }; }; @@ -64,10 +68,8 @@ blogPostSchema.statics.convertMarkdownToHtml = function(markdown) { }; blogPostSchema.statics.getPost = function(date, urlTitle, callback) { return blogPostModel.findOne({ - meta: { - date, - urlTitle - } + 'meta.date': date, + 'meta.urlTitle': urlTitle }, callback); }; diff --git a/routes/admin.js b/routes/admin.js index 91de6bf..9b60c5a 100644 --- a/routes/admin.js +++ b/routes/admin.js @@ -11,6 +11,7 @@ const passport = require('passport'); const common = require('../helpers/common'); const adminUserMiddleware = require('../middleware/admin-authentication'); const adminUser = require('../models/admin-user'); +const blogPost = require('../models/blog-post'); // display admin panel router.get('/admin', (req, res) => { @@ -123,6 +124,56 @@ router.get('/admin/api/v1/logout', adminUserMiddleware.adminAuthenticationRequir common.sendApiReturn(res, {}); }); +/* +* /admin/api/v1/newpost +* +* posts a new blog post +* +* post { +* content - content of the blog post in markdown +* title - title of the blog post +* author - id of the author +* category - category name of the blog post +* +* } +* return { +* code: http code +* success: boolean - true if login succesfull +* url: string | undefined - url of the blog post if successfull +* errors: Strings[messages] +* } +*/ +router.post('/admin/api/v1/newpost', adminUserMiddleware.adminAuthenticationRequired, function (req, res) { + + if (!req.body) return common.sendApiGenericError(res); + + const { content, title, author, category } = req.body; + const newBlogPost = new blogPost.blogPostModel({ + content: blogPost.blogPostModel.convertMarkdownToHtml(content), + name: title, + meta: { + author, + category, + urlTitle: title + .trim() + .replace(/\s/g, '-') + .replace(/[^A-z0-9-]/g, '') + .toLowerCase() + } + }); + + newBlogPost.save().then((post) => { + // successfull + common.sendApiReturn(res, { + url: common.convertDateToString(post.meta.date) + '/' + post.meta.urlTitle + }); + }).catch((rejection) => { + // TODO format exception so it doesnt have a huge list of errors + common.sendApiError(res, 500, [rejection]); + return; + }); +}); + // configure api 404 router.use('/admin/api', (req, res) => { common.sendApi404(res); diff --git a/routes/blog.js b/routes/blog.js index 7575367..f80aadf 100644 --- a/routes/blog.js +++ b/routes/blog.js @@ -12,15 +12,20 @@ const blogPostModel = require('../models/blog-post').blogPostModel; // display blog post 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())) { + // date format DD-MM-YYY + if (/[0-9]{4}-[0-9]{2}-[0-9]{2}/.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) => { + blogPostModel.getPost(new Date(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); + if (err || !post) { + console.log('error: ' + err + ' and post: ' + post); + return common.sendDefault404(res); + } // render blogpost - res.render('post', post.getBlogPostTemplateReady()); + res.render('post', { + post: post.getBlogPostTemplateReady() + }); }); } else { // params are incorrect diff --git a/views/admin.hbs b/views/admin.hbs index 1d4185f..88a4b36 100644 --- a/views/admin.hbs +++ b/views/admin.hbs @@ -20,7 +20,22 @@ +

create blog post

+
+

content

+ +

category

+ +

title

+ +

author id - yea, authors dont work yet. just ignore

+ + +
+
Check if logged in +
+ Logout {{> footer }} diff --git a/views/post.hbs b/views/post.hbs index b986f49..137c814 100644 --- a/views/post.hbs +++ b/views/post.hbs @@ -6,15 +6,15 @@ {{> navbar }}

blog post

-

{{ date }}

-

{{ category }}

+

{{ post.date }}

+

{{ post.category }}

- {{{ content }}} + {{{ post.content }}}
-

{{ author.name }} - {{ author.description }}

- + {{> footer }} From d41967816ce619879f10bbccaaaf2e399d8bb925 Mon Sep 17 00:00:00 2001 From: mrjvs Date: Sun, 14 Oct 2018 18:00:35 +0200 Subject: [PATCH 03/13] static text + progresslist post and edit + postauthor post and edit --- models/blog-post.js | 21 ++-- models/post-author.js | 10 +- models/progress-list.js | 36 +++++++ routes/admin.js | 212 ++++++++++++++++++++++++++++++++++++++++ routes/blog.js | 52 +++++++++- routes/progress.js | 60 ++++++++++++ server.js | 4 +- static-text.json | 4 + views/admin.hbs | 74 +++++++++++++- views/post.hbs | 7 +- views/progress.hbs | 15 +++ 11 files changed, 474 insertions(+), 21 deletions(-) create mode 100644 models/progress-list.js create mode 100644 routes/progress.js create mode 100644 static-text.json create mode 100644 views/progress.hbs diff --git a/models/blog-post.js b/models/blog-post.js index 642e5e8..01517ed 100644 --- a/models/blog-post.js +++ b/models/blog-post.js @@ -8,7 +8,7 @@ file containing the model file for a blog post // imports const mongoose = require('mongoose'); const common = require('../helpers/common'); -//const postAuthor = require('./post-author').postAuthorModel; +const postAuthor = require('./post-author').postAuthorModel; const showdown = require('showdown'); const converter = new showdown.Converter(); converter.setFlavor('github'); @@ -53,14 +53,17 @@ const blogPostSchema = new mongoose.Schema({ 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.methods.getBlogPostTemplateReady = function(callback) { + const self = this; + postAuthor.findById(this.meta.author, function (err, author) { + callback(err, { + content: self.content, + title: self.name, + date: self.meta.date, + category: self.meta.category, + author: author.getPostAuthorTemplateReady() + }); + }); }; blogPostSchema.statics.convertMarkdownToHtml = function(markdown) { diff --git a/models/post-author.js b/models/post-author.js index e3a5211..3bb1946 100644 --- a/models/post-author.js +++ b/models/post-author.js @@ -1,7 +1,7 @@ /* -blog-post.js - -file containing the model file for a blog post +post-author.js - +file containing the model for authors */ @@ -28,9 +28,9 @@ const postAuthorSchema = new mongoose.Schema({ postAuthorSchema.methods.getPostAuthorTemplateReady = function() { return { - authorName: this.name, - authorDescription: this.description, - authorProfilePicture: this.image + name: this.name, + description: this.description, + profilePicture: this.image }; }; diff --git a/models/progress-list.js b/models/progress-list.js new file mode 100644 index 0000000..d8f7fc3 --- /dev/null +++ b/models/progress-list.js @@ -0,0 +1,36 @@ +/* + +progress-list.js - +file containing the model for progress list + +*/ + +// imports +const mongoose = require('mongoose'); + +// progress text schema +const progressListSchema = new mongoose.Schema({ + state: { + type: Number, /* 0 - nothing, 1 - no support, 2 - partially working, 3 - works */ + default: 0 + }, + isGame: { + type: Boolean, /* true - is game list, false - is backend service */ + required: [true, 'isGame is required'] + }, + title: { + type: String, + required: [true, 'Title is required'] + }, + description: { + type: String, + required: [true, 'Description is required'] + } +}); + +const progressListModel = mongoose.model('progress', progressListSchema); + +module.exports = { + progressListModel, + progressListSchema +}; \ No newline at end of file diff --git a/routes/admin.js b/routes/admin.js index 9b60c5a..0590d22 100644 --- a/routes/admin.js +++ b/routes/admin.js @@ -12,6 +12,8 @@ const common = require('../helpers/common'); const adminUserMiddleware = require('../middleware/admin-authentication'); const adminUser = require('../models/admin-user'); const blogPost = require('../models/blog-post'); +const postAuthor = require('../models/post-author'); +const progressList = require('../models/progress-list'); // display admin panel router.get('/admin', (req, res) => { @@ -174,6 +176,216 @@ router.post('/admin/api/v1/newpost', adminUserMiddleware.adminAuthenticationRequ }); }); +/* +* /admin/api/v1/editpost +* +* edits a blog post +* +* post { +* id - id of the blog post to be edited +* content - content of the blog post IN HTML +* title - title of the blog post +* author - id of the author +* category - category name of the blog post +* } +* return { +* code: http code +* success: boolean - true if login succesfull +* url: string | undefined - url of the blog post if successfull +* errors: Strings[messages] +* } +*/ +router.post('/admin/api/v1/editpost', adminUserMiddleware.adminAuthenticationRequired, function (req, res) { + + if (!req.body) return common.sendApiGenericError(res); + + const { id, content, title, author, category } = req.body; + blogPost.blogPostModel.findByIdAndUpdate(id, { + 'content': content, + 'name': title, + 'meta.author': author, + 'meta.category': category + }, (err, post) => { + if (err) return common.sendApiError(res, 500, [err]); + common.sendApiReturn(res, { + url: common.convertDateToString(post.meta.date) + '/' + post.meta.urlTitle + }); + }); +}); + +/* +* /admin/api/v1/newauthor +* +* creates new author +* +* post { +* name - author name +* description - author description +* image - image url for profile picture +* } +* return { +* code: http code +* success: boolean - true if author succesfull +* id: string | undefined - id of the new author if successfull +* errors: Strings[messages] +* } +*/ +router.post('/admin/api/v1/newauthor', adminUserMiddleware.adminAuthenticationRequired, function (req, res) { + + if (!req.body) return common.sendApiGenericError(res); + + const { name, description, image } = req.body; + const newAuthor = new postAuthor.postAuthorModel({ + name, + description, + image + }); + + newAuthor.save().then((author) => { + // successfull + common.sendApiReturn(res, { + id: author.id + }); + }).catch((rejection) => { + // TODO format exception so it doesnt have a huge list of errors + common.sendApiError(res, 500, [rejection]); + return; + }); +}); + +/* +* /admin/api/v1/editauthor +* +* edit an existing author +* +* post { +* id - id of author to edit +* name - author name +* description - author description +* image - image url for profile picture +* } +* return { +* code: http code +* success: boolean - true if author succesfull +* id: String - id of the edited author +* errors: Strings[messages] +* } +*/ +router.post('/admin/api/v1/editauthor', adminUserMiddleware.adminAuthenticationRequired, function (req, res) { + + if (!req.body) return common.sendApiGenericError(res); + + const { id, name, description, image } = req.body; + + postAuthor.postAuthorModel.findByIdAndUpdate(id, { + name, + description, + image + }, (err, author) => { + // TODO format exception so it doesnt have a huge list of errors + if (err) return common.sendApiError(res, 500, [err]); + common.sendApiReturn(res, { + id: author.id + }); + }); +}); + +/* +* /admin/api/v1/newprogress +* +* creates a new progress entry +* +* post { +* title - progress entry name +* description - progress entry description +* state - 0: backend service entry, 1: no support, 2: partial support, 3: fullly working +* } +* return { +* code: http code +* success: boolean - true if progress succesfull +* id: String | undefined - sends if successfull +* errors: Strings[messages] +* } +*/ +router.post('/admin/api/v1/newprogress', adminUserMiddleware.adminAuthenticationRequired, function (req, res) { + + if (!req.body) return common.sendApiGenericError(res); + + const { title, description } = req.body; + let { state } = req.body; + let isGame = false; + if (state != '1' && state != '2' && state != '3') { + state = undefined; + } else { + state = parseInt(state); + isGame = true; + } + + const newProgress = new progressList.progressListModel({ + title, + description, + isGame, + state + }); + + newProgress.save().then((progress) => { + // successfull + common.sendApiReturn(res, { + id: progress.id + }); + }).catch((rejection) => { + // TODO format exception so it doesnt have a huge list of errors + common.sendApiError(res, 500, [rejection]); + return; + }); +}); + +/* +* /admin/api/v1/editprogress +* +* edit an existing progress entry +* +* post { +* title - progress entry name +* description - progress entry description +* state - 0: backend service entry, 1: no support, 2: partial support, 3: fullly working +* id - id of entry you want to edit +* } +* return { +* code: http code +* success: boolean - true if progress succesfull +* id: String - id of the edited progress entry +* errors: Strings[messages] +* } +*/ +router.post('/admin/api/v1/editprogress', adminUserMiddleware.adminAuthenticationRequired, function (req, res) { + + if (!req.body) return common.sendApiGenericError(res); + + const { title, description, id } = req.body; + let { state } = req.body; + let isGame = false; + if (state != '1' && state != '2' && state != '3') { + state = undefined; + } else { + state = parseInt(state); + isGame = true; + } + + progressList.progressListModel.findByIdAndUpdate(id, { + title, + description, + state, + isGame + }, (err, progress) => { + // TODO format exception so it doesnt have a huge list of errors + if (err) return common.sendApiError(res, 500, [err]); + common.sendApiReturn(res, { + id: progress.id + }); + }); +}); + // configure api 404 router.use('/admin/api', (req, res) => { common.sendApi404(res); diff --git a/routes/blog.js b/routes/blog.js index f80aadf..3ececa6 100644 --- a/routes/blog.js +++ b/routes/blog.js @@ -9,6 +9,7 @@ file for handling routes regarding blog posts. const router = require('express').Router(); const common = require('../helpers/common'); const blogPostModel = require('../models/blog-post').blogPostModel; +const postAuthorModel = require('../models/post-author').postAuthorModel; // display blog post router.get('/news/:date/:title', (req, res) => { @@ -23,8 +24,11 @@ router.get('/news/:date/:title', (req, res) => { } // render blogpost - res.render('post', { - post: post.getBlogPostTemplateReady() + post.getBlogPostTemplateReady((err, postTemplate) => { + if (err) return common.sendDefault404(res); + res.render('post', { + post: postTemplate + }); }); }); } else { @@ -33,5 +37,49 @@ router.get('/news/:date/:title', (req, res) => { } }); +/* +* /api/v1/listauthors +* +* gets a list of all authors +* +* return { +* code: http code +* success: boolean - true if author succesfull +* authorList: Objects[{_id, name, description, image}] - list of authors with information +* errors: Strings[messages] +* } +*/ +router.get('/api/v1/listauthors', function (req, res) { + postAuthorModel.find({}, (err, authors) => { + // TODO format exception so it doesnt have a huge list of errors + if (err) return common.sendApiError(res, 500, [err]); + common.sendApiReturn(res, { + authorList: authors + }); + }); +}); + +/* +* /api/v1/listblog +* +* gets a list of all posts +* +* return { +* code: http code +* success: boolean - true if post succesfull +* postList: Objects[{_id, content, meta}] - list of posts with information +* errors: Strings[messages] +* } +*/ +router.get('/api/v1/listblog', function (req, res) { + blogPostModel.find({}, (err, posts) => { + // TODO format exception so it doesnt have a huge list of errors + if (err) return common.sendApiError(res, 500, [err]); + common.sendApiReturn(res, { + postList: posts + }); + }); +}); + // export router module.exports = router; diff --git a/routes/progress.js b/routes/progress.js new file mode 100644 index 0000000..5e3b918 --- /dev/null +++ b/routes/progress.js @@ -0,0 +1,60 @@ +/* + +progress.js - +file for handling routes regarding progress + +*/ + +// imports +const router = require('express').Router(); +const common = require('../helpers/common'); +const staticText = require('../static-text.json'); +const progressListModel = require('../models/progress-list').progressListModel; + +// display progress +router.get('/progress', (req, res) => { + + progressListModel.find({}, (err, progress) => { + if (err) return common.sendDefault404(res); + console.log(progress); + let games = []; + let backends = []; + for (const i in progress) { + if (progress[i].isGame) + games += progress[i]; + else + backends += progress[i]; + } + console.log(games + backends); + res.render('progress', { + games, + backends, + summary: staticText.progressSummary + }); + }); +}); + +/* +* /api/v1/listprogress +* +* gets a list of progress +* +* return { +* code: http code +* success: boolean - true if progress succesfull +* progressList: Objects[{_id, title, description, state}] - list of progress with information +* errors: Strings[messages] +* } +*/ +router.get('/api/v1/listprogress', function (req, res) { + progressListModel.find({}, (err, progress) => { + // TODO format exception so it doesnt have a huge list of errors + if (err) return common.sendApiError(res, 500, [err]); + common.sendApiReturn(res, { + progressList: progress + }); + }); +}); + +// export router +module.exports = router; diff --git a/server.js b/server.js index 0191331..48ff28a 100644 --- a/server.js +++ b/server.js @@ -59,7 +59,8 @@ app.set('view engine', '.hbs'); const locations = { home: require('./routes/home'), posts: require('./routes/blog'), - admin: require('./routes/admin') + admin: require('./routes/admin'), + progress: require('./routes/progress') }; // static files @@ -68,6 +69,7 @@ app.use('/assets', express.static('assets')); app.use('/', locations.home); app.use('/', locations.posts); app.use('/', locations.admin); +app.use('/', locations.progress); app.use((req, res) => { common.sendDefault404(res); }); diff --git a/static-text.json b/static-text.json new file mode 100644 index 0000000..aa61ea6 --- /dev/null +++ b/static-text.json @@ -0,0 +1,4 @@ +{ + "progressSummary": "This is a progress summary", + "headerText": "A work-in-progress server replacement for nintendo 3ds and wiiu" +} \ No newline at end of file diff --git a/views/admin.hbs b/views/admin.hbs index 88a4b36..be0f55c 100644 --- a/views/admin.hbs +++ b/views/admin.hbs @@ -30,8 +30,80 @@

author id - yea, authors dont work yet. just ignore

- + + +

edit blog post

+
+

content

+ +

id

+ +

category

+ +

title

+ +

author id - yea, authors dont work yet. just ignore

+ + +
+ +

new author

+
+

name

+ +

description

+ +

image link

+ + +
+ +

edit author

+
+

id

+ +

name

+ +

description

+ +

image link

+ + +
+ +

new progress entry

+
+

title

+ +

description

+ +

state

+

0 - backend service
1 - no support
2 - partial support
3 - fully working

+ + +
+ +

edit progress entry

+
+

id

+ +

title

+ +

description

+ +

state

+

0 - backend service
1 - no support
2 - partial support
3 - fully working

+ + +
+ +
+ List of blog posts +
+ List of progress +
+ List of authors
Check if logged in
diff --git a/views/post.hbs b/views/post.hbs index 137c814..e20f425 100644 --- a/views/post.hbs +++ b/views/post.hbs @@ -5,7 +5,7 @@ {{> navbar }} -

blog post

+

{{ post.title }}

{{ post.date }}

{{ post.category }}

@@ -13,9 +13,10 @@ {{{ post.content }}} - +

{{ post.author.name }} - {{ post.author.description }}

+ {{> footer }} + diff --git a/views/progress.hbs b/views/progress.hbs new file mode 100644 index 0000000..63019f7 --- /dev/null +++ b/views/progress.hbs @@ -0,0 +1,15 @@ +

progress summary

+

{{ summary }}

+
+

game support

+{{#each games }} +{{ this.title }} +

{{ this.description }}

+

state: {{ this.state }}

+{{/each}} +

+

backend support

+{{#each backends }} +{{ this.title }} +

{{ this.description }}

+{{/each}} \ No newline at end of file From 5c291feffff996cc842e67182b5dddf222bc4f7f Mon Sep 17 00:00:00 2001 From: mrjvs Date: Sun, 14 Oct 2018 18:24:21 +0200 Subject: [PATCH 04/13] fixed progress types not sorting --- routes/progress.js | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/routes/progress.js b/routes/progress.js index 5e3b918..e6f4d0e 100644 --- a/routes/progress.js +++ b/routes/progress.js @@ -16,16 +16,10 @@ router.get('/progress', (req, res) => { progressListModel.find({}, (err, progress) => { if (err) return common.sendDefault404(res); - console.log(progress); - let games = []; - let backends = []; - for (const i in progress) { - if (progress[i].isGame) - games += progress[i]; - else - backends += progress[i]; - } - console.log(games + backends); + + const games = progress.filter(i => i.isGame); + const backends = progress.filter(i => !i.isGame); + res.render('progress', { games, backends, From 68f19d75b9e78f29531a339e2eda2479e1913745 Mon Sep 17 00:00:00 2001 From: mrjvs Date: Sun, 14 Oct 2018 19:29:33 +0200 Subject: [PATCH 05/13] added getting latest post --- models/blog-post.js | 21 +++++++++++++++++++++ routes/admin.js | 8 ++++++-- routes/blog.js | 20 +++++++++++++++++++- views/admin.hbs | 8 ++++++-- views/post-collection.hbs | 7 +++++++ 5 files changed, 59 insertions(+), 5 deletions(-) create mode 100644 views/post-collection.hbs diff --git a/models/blog-post.js b/models/blog-post.js index 01517ed..8ee89da 100644 --- a/models/blog-post.js +++ b/models/blog-post.js @@ -25,6 +25,10 @@ const blogPostSchema = new mongoose.Schema({ type: String, required: [true, 'Name is required'] }, + short: { + type: String, + required: [true, 'Short version is required'] + }, meta: { urlTitle: { type: String, @@ -65,6 +69,13 @@ blogPostSchema.methods.getBlogPostTemplateReady = function(callback) { }); }); }; +blogPostSchema.methods.getBlogPostShortTemplateReady = function() { + return { + content: this.short, + title: this.name, + url: common.convertDateToString(this.meta.date) + '/' + this.meta.urlTitle + }; +}; blogPostSchema.statics.convertMarkdownToHtml = function(markdown) { return converter.makeHtml(markdown); @@ -75,6 +86,16 @@ blogPostSchema.statics.getPost = function(date, urlTitle, callback) { 'meta.urlTitle': urlTitle }, callback); }; +// not tested +blogPostSchema.statics.getLatestBlogPostShortTemplateReady = function(amount, callback) { + blogPostModel.find({}).sort({'meta.date': 'desc'}).exec(function(err, posts) { + if (err) return callback(err); + let out = []; + for (let i = 0, l = posts.length; i < ( amount+1 < l ? amount+1 : l); i++) + out += posts[i].getBlogPostShortTemplateReady(); + callback(err, out); + }); +}; const blogPostModel = mongoose.model('blogPost', blogPostSchema); diff --git a/routes/admin.js b/routes/admin.js index 0590d22..b9509e0 100644 --- a/routes/admin.js +++ b/routes/admin.js @@ -135,6 +135,7 @@ router.get('/admin/api/v1/logout', adminUserMiddleware.adminAuthenticationRequir * content - content of the blog post in markdown * title - title of the blog post * author - id of the author +* short - short description of content in plain text * category - category name of the blog post * * } @@ -149,10 +150,11 @@ router.post('/admin/api/v1/newpost', adminUserMiddleware.adminAuthenticationRequ if (!req.body) return common.sendApiGenericError(res); - const { content, title, author, category } = req.body; + const { content, title, author, category, short } = req.body; const newBlogPost = new blogPost.blogPostModel({ content: blogPost.blogPostModel.convertMarkdownToHtml(content), name: title, + short, meta: { author, category, @@ -186,6 +188,7 @@ router.post('/admin/api/v1/newpost', adminUserMiddleware.adminAuthenticationRequ * content - content of the blog post IN HTML * title - title of the blog post * author - id of the author +* short - short description of content in plain text * category - category name of the blog post * } * return { @@ -199,10 +202,11 @@ router.post('/admin/api/v1/editpost', adminUserMiddleware.adminAuthenticationReq if (!req.body) return common.sendApiGenericError(res); - const { id, content, title, author, category } = req.body; + const { id, content, title, author, category, short } = req.body; blogPost.blogPostModel.findByIdAndUpdate(id, { 'content': content, 'name': title, + 'short': short, 'meta.author': author, 'meta.category': category }, (err, post) => { diff --git a/routes/blog.js b/routes/blog.js index 3ececa6..f6f8095 100644 --- a/routes/blog.js +++ b/routes/blog.js @@ -11,7 +11,7 @@ const common = require('../helpers/common'); const blogPostModel = require('../models/blog-post').blogPostModel; const postAuthorModel = require('../models/post-author').postAuthorModel; -// display blog post +// display single blog post router.get('/news/:date/:title', (req, res) => { // date format DD-MM-YYY if (/[0-9]{4}-[0-9]{2}-[0-9]{2}/.test(req.params.date) && /([a-z]|[0-9]|-)+/.test(req.params.title.toLowerCase())) { @@ -37,6 +37,24 @@ router.get('/news/:date/:title', (req, res) => { } }); +// display latest blogposts +router.get('/news', (req, res) => { + blogPostModel.find({}).sort({'meta.date': 'desc'}).exec(function(err, posts) { + if (err || !posts) { + return common.sendDefault404(res); + } + + const postCollection = []; + for (let i = 0, l = posts.length; i < l; i++) { + postCollection.push(posts[i].getBlogPostShortTemplateReady()); + } + + res.render('post-collection', { + posts: postCollection + }); + }); +}); + /* * /api/v1/listauthors * diff --git a/views/admin.hbs b/views/admin.hbs index be0f55c..50d192a 100644 --- a/views/admin.hbs +++ b/views/admin.hbs @@ -24,11 +24,13 @@

content

+

short version

+

category

title

-

author id - yea, authors dont work yet. just ignore

+

author id

@@ -37,13 +39,15 @@

content

+

short version

+

id

category

title

-

author id - yea, authors dont work yet. just ignore

+

author id

diff --git a/views/post-collection.hbs b/views/post-collection.hbs new file mode 100644 index 0000000..ca42724 --- /dev/null +++ b/views/post-collection.hbs @@ -0,0 +1,7 @@ +

Latest posts

+{{#each posts }} +{{ this.title }} +

{{ this.content }}

+link +

+{{/each}} \ No newline at end of file From 9e7626ffa1cda3dcb94288ad0a15a7567b76a16f Mon Sep 17 00:00:00 2001 From: mrjvs Date: Sun, 14 Oct 2018 19:39:27 +0200 Subject: [PATCH 06/13] updated gitignore and example static text --- .gitignore | 2 +- static-text.example.json | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) create mode 100644 static-text.example.json diff --git a/.gitignore b/.gitignore index d6b2614..aa48b01 100644 --- a/.gitignore +++ b/.gitignore @@ -59,4 +59,4 @@ typings/ # keep config and blog posts out of this config.json -posts/ \ No newline at end of file +static-text.json \ No newline at end of file diff --git a/static-text.example.json b/static-text.example.json new file mode 100644 index 0000000..aa61ea6 --- /dev/null +++ b/static-text.example.json @@ -0,0 +1,4 @@ +{ + "progressSummary": "This is a progress summary", + "headerText": "A work-in-progress server replacement for nintendo 3ds and wiiu" +} \ No newline at end of file From e649a165b257c7af5ac85395682af0492006aaa3 Mon Sep 17 00:00:00 2001 From: mrjvs Date: Sun, 14 Oct 2018 19:58:34 +0200 Subject: [PATCH 07/13] added delete admin user and list admin users --- routes/admin.js | 57 +++++++++++++++++++++++++++++++++++++++++++++++ setupAdminUser.js | 12 ++++++++++ views/admin.hbs | 9 ++++++++ 3 files changed, 78 insertions(+) create mode 100644 setupAdminUser.js diff --git a/routes/admin.js b/routes/admin.js index b9509e0..28526e0 100644 --- a/routes/admin.js +++ b/routes/admin.js @@ -90,6 +90,63 @@ router.post('/admin/api/v1/register', adminUserMiddleware.adminAuthenticationReq }); }); +/* +* /admin/api/v1/removeadmin +* - requires admin auth +* +* registers a new admin user +* +* post { +* id - id of the admin user +* } +* return { +* code: httpcode +* success: boolean - true if delete was successull +* errors: Strings[messages] +* } +*/ +router.post('/admin/api/v1/removeadmin', adminUserMiddleware.adminAuthenticationRequired, (req, res) => { + if (!req.body) { + common.sendApiGenericError(res); + return; + } + + const { id } = req.body; + adminUser.adminUserModel.findByIdAndDelete(id, (err) => { + if (err) return common.sendApiError(res, 500, [err]); + // successfull + common.sendApiReturn(res, {}); + }); +}); + +/* +* /admin/api/v1/listadmins +* - requires admin auth +* +* gets list of admins +* +* return { +* code: httpcode +* success: boolean - true if delete was successull +* errors: Strings[messages] +* } +*/ +router.get('/admin/api/v1/listadmins', adminUserMiddleware.adminAuthenticationRequired, (req, res) => { + adminUser.adminUserModel.find({}, (err, admins) => { + // TODO format exception so it doesnt have a huge list of errors + if (err) return common.sendApiError(res, 500, [err]); + + const output = []; + for (let i = 0, l = admins.length; i < l; i++) { + admins[i].password = undefined; + output.push(admins[i]); + } + common.sendApiReturn(res, { + admins: output + }); + }); +}); + /* * /admin/api/v1/check * diff --git a/setupAdminUser.js b/setupAdminUser.js new file mode 100644 index 0000000..3b4fe24 --- /dev/null +++ b/setupAdminUser.js @@ -0,0 +1,12 @@ +const adminUser = require('./models/admin-user'); + +const newUser = new adminUser.adminUserModel({ + username: 'admin', + password: 'root' +}); + +newUser.save().then(() => { + console.log('success, user admin pass root'); +}).catch((rejection) => { + console.log(rejection); +}); \ No newline at end of file diff --git a/views/admin.hbs b/views/admin.hbs index 50d192a..c328c18 100644 --- a/views/admin.hbs +++ b/views/admin.hbs @@ -20,6 +20,13 @@ +

delete admin

+
+

id

+ + +
+

create blog post

content

@@ -102,6 +109,8 @@
+
+ List of admin users
List of blog posts
From affb7fc36a3f0ece83a7dda07c79375630259525 Mon Sep 17 00:00:00 2001 From: mrjvs Date: Sun, 14 Oct 2018 20:36:17 +0200 Subject: [PATCH 08/13] added contact page with functionality --- config.example.json | 5 +++ routes/contact.js | 74 +++++++++++++++++++++++++++++++++++++++++++++ routes/home.js | 5 --- server.js | 2 ++ views/contact.hbs | 11 ++++++- 5 files changed, 91 insertions(+), 6 deletions(-) create mode 100644 routes/contact.js diff --git a/config.example.json b/config.example.json index cb5f1ab..98a25e6 100644 --- a/config.example.json +++ b/config.example.json @@ -5,6 +5,11 @@ "database": { "url": "mongodb://localhost:27017/pretendo_website" }, + "contactWebhook": { + "port": 443, + "host": "host.com", + "path": "/webhookurl" + }, "secrets": { "session": "session secret here" } diff --git a/routes/contact.js b/routes/contact.js new file mode 100644 index 0000000..f284f3f --- /dev/null +++ b/routes/contact.js @@ -0,0 +1,74 @@ +/* + +contact.js - +file for handling routes regarding contact + +*/ + +// imports +const router = require('express').Router(); +const common = require('../helpers/common'); +const config = require('../config.json'); +const https = require('https'); + +// display contact page +router.get('/contact', (req, res) => { + res.render('contact'); +}); + +/* +* /api/v1/sendmessage +* +* registers a new admin user +* +* post { +* email - email of sender +* subject - subject of message +* message - actual message +* } +* return { +* code: httpcode +* success: boolean - true if sending was successull +* errors: Strings[messages] +* } +*/ +router.post('/api/v1/sendmessage', function (req, res) { + if (!req.body) return common.sendApiGenericError(res); + + const { email, subject, message } = req.body; + if (email && subject && message && message.length < 2000) { + console.log('checks passed'); + const postData = JSON.stringify({ + content: 'email: ' + email + ' \n subject: ' + subject + ' \n\n' + message + }); + + const request = https.request({ + hostname: config.contactWebhook.host, + port: config.contactWebhook.port, + path: config.contactWebhook.path, + method : 'POST', + headers : { + 'Content-Type': 'application/json', + 'Cache-Control': 'no-cache', + 'Content-Length': postData.length + } + }, () => { + common.sendApiReturn(res, {}); + }); + + request.on('error', (e) => { + common.sendApiGenericError(res); + console.log('request errored' + e); + }); + + request.write(postData); + request.end(); + } else { + // TODO give more detailed response + return common.sendApiGenericError(res); + } + +}); + +// export router +module.exports = router; diff --git a/routes/home.js b/routes/home.js index 38c9045..5af1ab2 100644 --- a/routes/home.js +++ b/routes/home.js @@ -14,10 +14,5 @@ router.get('/', (req, res) => { res.render('home'); }); -// display contact page -router.get('/contact', (req, res) => { - res.render('contact'); -}); - // export the router module.exports = router; diff --git a/server.js b/server.js index 48ff28a..dfad964 100644 --- a/server.js +++ b/server.js @@ -60,6 +60,7 @@ const locations = { home: require('./routes/home'), posts: require('./routes/blog'), admin: require('./routes/admin'), + contact: require('./routes/contact'), progress: require('./routes/progress') }; @@ -67,6 +68,7 @@ const locations = { app.use('/assets', express.static('assets')); // page map app.use('/', locations.home); +app.use('/', locations.contact); app.use('/', locations.posts); app.use('/', locations.admin); app.use('/', locations.progress); diff --git a/views/contact.hbs b/views/contact.hbs index bea14ac..51fd7a7 100644 --- a/views/contact.hbs +++ b/views/contact.hbs @@ -5,7 +5,16 @@ {{> navbar }} -

contact form here

+

contact form

+
+

content

+ +

subject

+ +

email

+ + +
{{> footer }} From 5eb80dff81e28b4cba7f227ccdc50ed3e5e83b40 Mon Sep 17 00:00:00 2001 From: mrjvs Date: Tue, 16 Oct 2018 14:59:35 +0200 Subject: [PATCH 09/13] renamed urlTitle to slug since thats what it should be --- models/blog-post.js | 8 ++++---- routes/admin.js | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/models/blog-post.js b/models/blog-post.js index 8ee89da..1bf656e 100644 --- a/models/blog-post.js +++ b/models/blog-post.js @@ -30,7 +30,7 @@ const blogPostSchema = new mongoose.Schema({ required: [true, 'Short version is required'] }, meta: { - urlTitle: { + slug: { type: String, required: [true, 'Author is required'], trim: true @@ -73,17 +73,17 @@ blogPostSchema.methods.getBlogPostShortTemplateReady = function() { return { content: this.short, title: this.name, - url: common.convertDateToString(this.meta.date) + '/' + this.meta.urlTitle + url: common.convertDateToString(this.meta.date) + '/' + this.meta.slug }; }; blogPostSchema.statics.convertMarkdownToHtml = function(markdown) { return converter.makeHtml(markdown); }; -blogPostSchema.statics.getPost = function(date, urlTitle, callback) { +blogPostSchema.statics.getPost = function(date, slug, callback) { return blogPostModel.findOne({ 'meta.date': date, - 'meta.urlTitle': urlTitle + 'meta.slug': slug }, callback); }; // not tested diff --git a/routes/admin.js b/routes/admin.js index 28526e0..006733f 100644 --- a/routes/admin.js +++ b/routes/admin.js @@ -215,7 +215,7 @@ router.post('/admin/api/v1/newpost', adminUserMiddleware.adminAuthenticationRequ meta: { author, category, - urlTitle: title + slug: title .trim() .replace(/\s/g, '-') .replace(/[^A-z0-9-]/g, '') @@ -226,7 +226,7 @@ router.post('/admin/api/v1/newpost', adminUserMiddleware.adminAuthenticationRequ newBlogPost.save().then((post) => { // successfull common.sendApiReturn(res, { - url: common.convertDateToString(post.meta.date) + '/' + post.meta.urlTitle + url: common.convertDateToString(post.meta.date) + '/' + post.meta.slug }); }).catch((rejection) => { // TODO format exception so it doesnt have a huge list of errors @@ -269,7 +269,7 @@ router.post('/admin/api/v1/editpost', adminUserMiddleware.adminAuthenticationReq }, (err, post) => { if (err) return common.sendApiError(res, 500, [err]); common.sendApiReturn(res, { - url: common.convertDateToString(post.meta.date) + '/' + post.meta.urlTitle + url: common.convertDateToString(post.meta.date) + '/' + post.meta.slug }); }); }); From eee42ab329eb2f84dc0eeee700b2d12a3863b455 Mon Sep 17 00:00:00 2001 From: mrjvs Date: Tue, 16 Oct 2018 15:20:06 +0200 Subject: [PATCH 10/13] refactored helpers into seperate files --- helpers/{common.js => api.js} | 23 +--------- helpers/util.js | 15 +++++++ middleware/admin-authentication.js | 4 +- models/blog-post.js | 5 ++- package-lock.json | 5 +++ package.json | 1 + routes/admin.js | 67 +++++++++++++++--------------- routes/blog.js | 19 +++++---- routes/contact.js | 10 ++--- routes/progress.js | 9 ++-- server.js | 4 +- 11 files changed, 83 insertions(+), 79 deletions(-) rename helpers/{common.js => api.js} (72%) create mode 100644 helpers/util.js diff --git a/helpers/common.js b/helpers/api.js similarity index 72% rename from helpers/common.js rename to helpers/api.js index 6143096..b98c8c6 100644 --- a/helpers/common.js +++ b/helpers/api.js @@ -1,15 +1,3 @@ -/* - -common.js - -common page functionality. - -*/ - -// shows 404 template. -function sendDefault404(res) { - res.status(404).send('404'); -} - // use for any api return. it has basic layout used for every return. function sendApiReturn(res, data, errors) { res.status(200).json( @@ -63,19 +51,10 @@ function sendApiError(res, code, errors) { }); } -// convert date to string -function convertDateToString(date) { - return date.getUTCFullYear() + '-' + - ('0' + (date.getUTCMonth()+1)).slice(-2) + '-' + - ('0' + date.getUTCDate()).slice(-2); -} - module.exports = { - sendDefault404, sendApiReturn, sendApi404, sendApiGenericError, sendApiError, - sendApiAuthError, - convertDateToString + sendApiAuthError }; \ No newline at end of file diff --git a/helpers/util.js b/helpers/util.js new file mode 100644 index 0000000..00e8e3d --- /dev/null +++ b/helpers/util.js @@ -0,0 +1,15 @@ +/* + +util.js - +small commonly used utilities + +*/ + +// shows 404 template. +function sendDefault404(res) { + res.status(404).send('404'); +} + +module.exports = { + sendDefault404 +}; \ No newline at end of file diff --git a/middleware/admin-authentication.js b/middleware/admin-authentication.js index 4717352..160132e 100644 --- a/middleware/admin-authentication.js +++ b/middleware/admin-authentication.js @@ -6,14 +6,14 @@ Middleware file for authentication checking */ // imports -const common = require('../helpers/common'); +const apiHelper = require('../helpers/api'); // middleware to use if admin authentication is required function adminAuthenticationRequired(req, res, next) { if (req.isAuthenticated() && req.user.role && req.user.role === 'admin') { return next(); } else { - common.sendApiAuthError(res); + apiHelper.sendApiAuthError(res); } } diff --git a/models/blog-post.js b/models/blog-post.js index 1bf656e..4d966d1 100644 --- a/models/blog-post.js +++ b/models/blog-post.js @@ -10,6 +10,7 @@ const mongoose = require('mongoose'); const common = require('../helpers/common'); const postAuthor = require('./post-author').postAuthorModel; const showdown = require('showdown'); +const moment = require('moment'); const converter = new showdown.Converter(); converter.setFlavor('github'); @@ -43,7 +44,7 @@ const blogPostSchema = new mongoose.Schema({ date: { type: Date, default: () => { - return new Date(common.convertDateToString(new Date())); + return new Date(moment(new Date(), 'YYYY-MM-DD')); } }, category: { @@ -73,7 +74,7 @@ blogPostSchema.methods.getBlogPostShortTemplateReady = function() { return { content: this.short, title: this.name, - url: common.convertDateToString(this.meta.date) + '/' + this.meta.slug + url: moment(this.meta.date, 'YYYY-MM-DD') + '/' + this.meta.slug }; }; diff --git a/package-lock.json b/package-lock.json index c3a9751..205475e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1746,6 +1746,11 @@ } } }, + "moment": { + "version": "2.22.2", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.22.2.tgz", + "integrity": "sha1-PCV/mDn8DpP/UxSWMiOeuQeD/2Y=" + }, "mongodb": { "version": "3.1.6", "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.1.6.tgz", diff --git a/package.json b/package.json index c7b1948..fff669b 100644 --- a/package.json +++ b/package.json @@ -22,6 +22,7 @@ "express": "^4.16.2", "express-handlebars": "^3.0.0", "express-session": "^1.15.6", + "moment": "^2.22.2", "mongoose": "^5.3.2", "mongoose-unique-validator": "^2.0.2", "passport": "^0.4.0", diff --git a/routes/admin.js b/routes/admin.js index 006733f..0853375 100644 --- a/routes/admin.js +++ b/routes/admin.js @@ -8,7 +8,8 @@ file for handling admin panel routes // imports const router = require('express').Router(); const passport = require('passport'); -const common = require('../helpers/common'); +const moment = require('moment'); +const apiHelper = require('../helpers/api'); const adminUserMiddleware = require('../middleware/admin-authentication'); const adminUser = require('../models/admin-user'); const blogPost = require('../models/blog-post'); @@ -39,7 +40,7 @@ router.get('/admin', (req, res) => { */ // TODO make login somehow display errors in correct format. router.post('/admin/api/v1/login', passport.authenticate('adminUserStrategy'), function (req, res) { - common.sendApiReturn(res, { + apiHelper.sendApiReturn(res, { username: req.user.username, role: req.user.role ? req.user.role : undefined }); @@ -66,7 +67,7 @@ router.post('/admin/api/v1/login', passport.authenticate('adminUserStrategy'), f router.post('/admin/api/v1/register', adminUserMiddleware.adminAuthenticationRequired, (req, res) => { if (!req.body) { // no post body - common.sendApiGenericError(res); + apiHelper.sendApiGenericError(res); return; } @@ -78,14 +79,14 @@ router.post('/admin/api/v1/register', adminUserMiddleware.adminAuthenticationReq newUser.save().then(() => { // successfull - common.sendApiReturn(res, { + apiHelper.sendApiReturn(res, { username: req.user.username, role: req.user.role ? req.user.role : undefined }); return; }).catch((rejection) => { // TODO format exception so it doesnt have a huge list of errors - common.sendApiError(res, 500, [rejection]); + apiHelper.sendApiError(res, 500, [rejection]); return; }); }); @@ -107,15 +108,15 @@ router.post('/admin/api/v1/register', adminUserMiddleware.adminAuthenticationReq */ router.post('/admin/api/v1/removeadmin', adminUserMiddleware.adminAuthenticationRequired, (req, res) => { if (!req.body) { - common.sendApiGenericError(res); + apiHelper.sendApiGenericError(res); return; } const { id } = req.body; adminUser.adminUserModel.findByIdAndDelete(id, (err) => { - if (err) return common.sendApiError(res, 500, [err]); + if (err) return apiHelper.sendApiError(res, 500, [err]); // successfull - common.sendApiReturn(res, {}); + apiHelper.sendApiReturn(res, {}); }); }); @@ -134,14 +135,14 @@ router.post('/admin/api/v1/removeadmin', adminUserMiddleware.adminAuthentication router.get('/admin/api/v1/listadmins', adminUserMiddleware.adminAuthenticationRequired, (req, res) => { adminUser.adminUserModel.find({}, (err, admins) => { // TODO format exception so it doesnt have a huge list of errors - if (err) return common.sendApiError(res, 500, [err]); + if (err) return apiHelper.sendApiError(res, 500, [err]); const output = []; for (let i = 0, l = admins.length; i < l; i++) { admins[i].password = undefined; output.push(admins[i]); } - common.sendApiReturn(res, { + apiHelper.sendApiReturn(res, { admins: output }); }); @@ -161,7 +162,7 @@ router.get('/admin/api/v1/listadmins', adminUserMiddleware.adminAuthenticationRe * } */ router.get('/admin/api/v1/check', adminUserMiddleware.authenticationOptional, (req, res) => { - common.sendApiReturn(res, { + apiHelper.sendApiReturn(res, { isAuthed: req.user ? true : false, role: req.user ? (req.user.role ? req.user.role : undefined) : undefined }); @@ -180,7 +181,7 @@ router.get('/admin/api/v1/check', adminUserMiddleware.authenticationOptional, (r */ router.get('/admin/api/v1/logout', adminUserMiddleware.adminAuthenticationRequired, (req, res) => { req.logout(); - common.sendApiReturn(res, {}); + apiHelper.sendApiReturn(res, {}); }); /* @@ -205,7 +206,7 @@ router.get('/admin/api/v1/logout', adminUserMiddleware.adminAuthenticationRequir */ router.post('/admin/api/v1/newpost', adminUserMiddleware.adminAuthenticationRequired, function (req, res) { - if (!req.body) return common.sendApiGenericError(res); + if (!req.body) return apiHelper.sendApiGenericError(res); const { content, title, author, category, short } = req.body; const newBlogPost = new blogPost.blogPostModel({ @@ -225,12 +226,12 @@ router.post('/admin/api/v1/newpost', adminUserMiddleware.adminAuthenticationRequ newBlogPost.save().then((post) => { // successfull - common.sendApiReturn(res, { - url: common.convertDateToString(post.meta.date) + '/' + post.meta.slug + apiHelper.sendApiReturn(res, { + url: moment(post.meta.date, 'YYYY-MM-DD') + '/' + post.meta.slug }); }).catch((rejection) => { // TODO format exception so it doesnt have a huge list of errors - common.sendApiError(res, 500, [rejection]); + apiHelper.sendApiError(res, 500, [rejection]); return; }); }); @@ -257,7 +258,7 @@ router.post('/admin/api/v1/newpost', adminUserMiddleware.adminAuthenticationRequ */ router.post('/admin/api/v1/editpost', adminUserMiddleware.adminAuthenticationRequired, function (req, res) { - if (!req.body) return common.sendApiGenericError(res); + if (!req.body) return apiHelper.sendApiGenericError(res); const { id, content, title, author, category, short } = req.body; blogPost.blogPostModel.findByIdAndUpdate(id, { @@ -267,9 +268,9 @@ router.post('/admin/api/v1/editpost', adminUserMiddleware.adminAuthenticationReq 'meta.author': author, 'meta.category': category }, (err, post) => { - if (err) return common.sendApiError(res, 500, [err]); - common.sendApiReturn(res, { - url: common.convertDateToString(post.meta.date) + '/' + post.meta.slug + if (err) return apiHelper.sendApiError(res, 500, [err]); + apiHelper.sendApiReturn(res, { + url: moment(post.meta.date, 'YYYY-MM-DD') + '/' + post.meta.slug }); }); }); @@ -293,7 +294,7 @@ router.post('/admin/api/v1/editpost', adminUserMiddleware.adminAuthenticationReq */ router.post('/admin/api/v1/newauthor', adminUserMiddleware.adminAuthenticationRequired, function (req, res) { - if (!req.body) return common.sendApiGenericError(res); + if (!req.body) return apiHelper.sendApiGenericError(res); const { name, description, image } = req.body; const newAuthor = new postAuthor.postAuthorModel({ @@ -304,12 +305,12 @@ router.post('/admin/api/v1/newauthor', adminUserMiddleware.adminAuthenticationRe newAuthor.save().then((author) => { // successfull - common.sendApiReturn(res, { + apiHelper.sendApiReturn(res, { id: author.id }); }).catch((rejection) => { // TODO format exception so it doesnt have a huge list of errors - common.sendApiError(res, 500, [rejection]); + apiHelper.sendApiError(res, 500, [rejection]); return; }); }); @@ -334,7 +335,7 @@ router.post('/admin/api/v1/newauthor', adminUserMiddleware.adminAuthenticationRe */ router.post('/admin/api/v1/editauthor', adminUserMiddleware.adminAuthenticationRequired, function (req, res) { - if (!req.body) return common.sendApiGenericError(res); + if (!req.body) return apiHelper.sendApiGenericError(res); const { id, name, description, image } = req.body; @@ -344,8 +345,8 @@ router.post('/admin/api/v1/editauthor', adminUserMiddleware.adminAuthenticationR image }, (err, author) => { // TODO format exception so it doesnt have a huge list of errors - if (err) return common.sendApiError(res, 500, [err]); - common.sendApiReturn(res, { + if (err) return apiHelper.sendApiError(res, 500, [err]); + apiHelper.sendApiReturn(res, { id: author.id }); }); @@ -370,7 +371,7 @@ router.post('/admin/api/v1/editauthor', adminUserMiddleware.adminAuthenticationR */ router.post('/admin/api/v1/newprogress', adminUserMiddleware.adminAuthenticationRequired, function (req, res) { - if (!req.body) return common.sendApiGenericError(res); + if (!req.body) return apiHelper.sendApiGenericError(res); const { title, description } = req.body; let { state } = req.body; @@ -391,12 +392,12 @@ router.post('/admin/api/v1/newprogress', adminUserMiddleware.adminAuthentication newProgress.save().then((progress) => { // successfull - common.sendApiReturn(res, { + apiHelper.sendApiReturn(res, { id: progress.id }); }).catch((rejection) => { // TODO format exception so it doesnt have a huge list of errors - common.sendApiError(res, 500, [rejection]); + apiHelper.sendApiError(res, 500, [rejection]); return; }); }); @@ -421,7 +422,7 @@ router.post('/admin/api/v1/newprogress', adminUserMiddleware.adminAuthentication */ router.post('/admin/api/v1/editprogress', adminUserMiddleware.adminAuthenticationRequired, function (req, res) { - if (!req.body) return common.sendApiGenericError(res); + if (!req.body) return apiHelper.sendApiGenericError(res); const { title, description, id } = req.body; let { state } = req.body; @@ -440,8 +441,8 @@ router.post('/admin/api/v1/editprogress', adminUserMiddleware.adminAuthenticatio isGame }, (err, progress) => { // TODO format exception so it doesnt have a huge list of errors - if (err) return common.sendApiError(res, 500, [err]); - common.sendApiReturn(res, { + if (err) return apiHelper.sendApiError(res, 500, [err]); + apiHelper.sendApiReturn(res, { id: progress.id }); }); @@ -449,7 +450,7 @@ router.post('/admin/api/v1/editprogress', adminUserMiddleware.adminAuthenticatio // configure api 404 router.use('/admin/api', (req, res) => { - common.sendApi404(res); + apiHelper.sendApi404(res); }); // export the router diff --git a/routes/blog.js b/routes/blog.js index f6f8095..273afe5 100644 --- a/routes/blog.js +++ b/routes/blog.js @@ -7,7 +7,8 @@ file for handling routes regarding blog posts. // imports const router = require('express').Router(); -const common = require('../helpers/common'); +const apiHelper = require('../helpers/api'); +const utilHelper = require('../helpers/util'); const blogPostModel = require('../models/blog-post').blogPostModel; const postAuthorModel = require('../models/post-author').postAuthorModel; @@ -20,12 +21,12 @@ router.get('/news/:date/:title', (req, res) => { // error exists or no post exists with the date and name if (err || !post) { console.log('error: ' + err + ' and post: ' + post); - return common.sendDefault404(res); + return utilHelper.sendDefault404(res); } // render blogpost post.getBlogPostTemplateReady((err, postTemplate) => { - if (err) return common.sendDefault404(res); + if (err) return utilHelper.sendDefault404(res); res.render('post', { post: postTemplate }); @@ -33,7 +34,7 @@ router.get('/news/:date/:title', (req, res) => { }); } else { // params are incorrect - common.sendDefault404(res); + utilHelper.sendDefault404(res); } }); @@ -41,7 +42,7 @@ router.get('/news/:date/:title', (req, res) => { router.get('/news', (req, res) => { blogPostModel.find({}).sort({'meta.date': 'desc'}).exec(function(err, posts) { if (err || !posts) { - return common.sendDefault404(res); + return utilHelper.sendDefault404(res); } const postCollection = []; @@ -70,8 +71,8 @@ router.get('/news', (req, res) => { router.get('/api/v1/listauthors', function (req, res) { postAuthorModel.find({}, (err, authors) => { // TODO format exception so it doesnt have a huge list of errors - if (err) return common.sendApiError(res, 500, [err]); - common.sendApiReturn(res, { + if (err) return apiHelper.sendApiError(res, 500, [err]); + apiHelper.sendApiReturn(res, { authorList: authors }); }); @@ -92,8 +93,8 @@ router.get('/api/v1/listauthors', function (req, res) { router.get('/api/v1/listblog', function (req, res) { blogPostModel.find({}, (err, posts) => { // TODO format exception so it doesnt have a huge list of errors - if (err) return common.sendApiError(res, 500, [err]); - common.sendApiReturn(res, { + if (err) return apiHelper.sendApiError(res, 500, [err]); + apiHelper.sendApiReturn(res, { postList: posts }); }); diff --git a/routes/contact.js b/routes/contact.js index f284f3f..627e4df 100644 --- a/routes/contact.js +++ b/routes/contact.js @@ -7,7 +7,7 @@ file for handling routes regarding contact // imports const router = require('express').Router(); -const common = require('../helpers/common'); +const apiHelper = require('../helpers/api'); const config = require('../config.json'); const https = require('https'); @@ -33,7 +33,7 @@ router.get('/contact', (req, res) => { * } */ router.post('/api/v1/sendmessage', function (req, res) { - if (!req.body) return common.sendApiGenericError(res); + if (!req.body) return apiHelper.sendApiGenericError(res); const { email, subject, message } = req.body; if (email && subject && message && message.length < 2000) { @@ -53,11 +53,11 @@ router.post('/api/v1/sendmessage', function (req, res) { 'Content-Length': postData.length } }, () => { - common.sendApiReturn(res, {}); + apiHelper.sendApiReturn(res, {}); }); request.on('error', (e) => { - common.sendApiGenericError(res); + apiHelper.sendApiGenericError(res); console.log('request errored' + e); }); @@ -65,7 +65,7 @@ router.post('/api/v1/sendmessage', function (req, res) { request.end(); } else { // TODO give more detailed response - return common.sendApiGenericError(res); + return apiHelper.sendApiGenericError(res); } }); diff --git a/routes/progress.js b/routes/progress.js index e6f4d0e..3ad5430 100644 --- a/routes/progress.js +++ b/routes/progress.js @@ -7,7 +7,8 @@ file for handling routes regarding progress // imports const router = require('express').Router(); -const common = require('../helpers/common'); +const apiHelper = require('../helpers/api'); +const utilHelper = require('../helpers/util'); const staticText = require('../static-text.json'); const progressListModel = require('../models/progress-list').progressListModel; @@ -15,7 +16,7 @@ const progressListModel = require('../models/progress-list').progressListModel; router.get('/progress', (req, res) => { progressListModel.find({}, (err, progress) => { - if (err) return common.sendDefault404(res); + if (err) return apiHelper.sendDefault404(res); const games = progress.filter(i => i.isGame); const backends = progress.filter(i => !i.isGame); @@ -43,8 +44,8 @@ router.get('/progress', (req, res) => { router.get('/api/v1/listprogress', function (req, res) { progressListModel.find({}, (err, progress) => { // TODO format exception so it doesnt have a huge list of errors - if (err) return common.sendApiError(res, 500, [err]); - common.sendApiReturn(res, { + if (err) return apiHelper.sendApiError(res, 500, [err]); + apiHelper.sendApiReturn(res, { progressList: progress }); }); diff --git a/server.js b/server.js index dfad964..a934f94 100644 --- a/server.js +++ b/server.js @@ -13,7 +13,7 @@ const mongoStore = require('connect-mongo')(session); const mongoose = require('mongoose'); const bodyParser = require('body-parser'); const config = require('./config.json'); -const common = require('./helpers/common'); +const utilHelper = require('./helpers/util'); const passportconfig = require('./passport.config.js'); // setup console colors @@ -73,7 +73,7 @@ app.use('/', locations.posts); app.use('/', locations.admin); app.use('/', locations.progress); app.use((req, res) => { - common.sendDefault404(res); + utilHelper.sendDefault404(res); }); // TODO improve error handling From 47ea7b157b7008ed53633840fb089b3ee5812834 Mon Sep 17 00:00:00 2001 From: mrjvs Date: Tue, 16 Oct 2018 15:22:07 +0200 Subject: [PATCH 11/13] oof, forgot to save some files --- models/blog-post.js | 1 - routes/progress.js | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/models/blog-post.js b/models/blog-post.js index 4d966d1..c52de36 100644 --- a/models/blog-post.js +++ b/models/blog-post.js @@ -7,7 +7,6 @@ file containing the model file for a blog post // imports const mongoose = require('mongoose'); -const common = require('../helpers/common'); const postAuthor = require('./post-author').postAuthorModel; const showdown = require('showdown'); const moment = require('moment'); diff --git a/routes/progress.js b/routes/progress.js index 3ad5430..76ce1b9 100644 --- a/routes/progress.js +++ b/routes/progress.js @@ -16,7 +16,7 @@ const progressListModel = require('../models/progress-list').progressListModel; router.get('/progress', (req, res) => { progressListModel.find({}, (err, progress) => { - if (err) return apiHelper.sendDefault404(res); + if (err) return utilHelper.sendDefault404(res); const games = progress.filter(i => i.isGame); const backends = progress.filter(i => !i.isGame); From 815e5aba03b8cfb560fe9f68372e2d174abeadac Mon Sep 17 00:00:00 2001 From: mrjvs Date: Tue, 16 Oct 2018 16:12:36 +0200 Subject: [PATCH 12/13] update comments --- helpers/api.js | 7 ++++++ helpers/util.js | 2 +- middleware/admin-authentication.js | 2 +- models/admin-user.js | 1 + models/blog-post.js | 2 ++ models/post-author.js | 1 + models/progress-list.js | 2 +- passport.config.js | 2 +- routes/admin.js | 35 ++++++++++++++++++++---------- routes/blog.js | 4 +++- routes/contact.js | 7 +++++- routes/progress.js | 1 + server.js | 1 + 13 files changed, 49 insertions(+), 18 deletions(-) diff --git a/helpers/api.js b/helpers/api.js index b98c8c6..958b321 100644 --- a/helpers/api.js +++ b/helpers/api.js @@ -1,3 +1,10 @@ +/* + +api.js - +common api returns + +*/ + // use for any api return. it has basic layout used for every return. function sendApiReturn(res, data, errors) { res.status(200).json( diff --git a/helpers/util.js b/helpers/util.js index 00e8e3d..cff7eba 100644 --- a/helpers/util.js +++ b/helpers/util.js @@ -5,7 +5,7 @@ small commonly used utilities */ -// shows 404 template. +// shows 404 template. takes express response object function sendDefault404(res) { res.status(404).send('404'); } diff --git a/middleware/admin-authentication.js b/middleware/admin-authentication.js index 160132e..85f391d 100644 --- a/middleware/admin-authentication.js +++ b/middleware/admin-authentication.js @@ -17,7 +17,7 @@ function adminAuthenticationRequired(req, res, next) { } } -// middleware to use if authentication +// middleware to use if authentication is optional function authenticationOptional(req, res, next) { return next(); } diff --git a/models/admin-user.js b/models/admin-user.js index 5240dbc..84a7127 100644 --- a/models/admin-user.js +++ b/models/admin-user.js @@ -20,6 +20,7 @@ const adminUserSchema = new mongoose.Schema({ unique: true, trim: true }, + // non hashed, gets hashed at save password: { type: String, required: [true, 'Password is required.'], diff --git a/models/blog-post.js b/models/blog-post.js index c52de36..c8ee610 100644 --- a/models/blog-post.js +++ b/models/blog-post.js @@ -21,10 +21,12 @@ const blogPostSchema = new mongoose.Schema({ required: [true, 'Content is required.'], trim: true }, + // title of blog post name: { type: String, required: [true, 'Name is required'] }, + // short description of blog post short: { type: String, required: [true, 'Short version is required'] diff --git a/models/post-author.js b/models/post-author.js index 3bb1946..66904b5 100644 --- a/models/post-author.js +++ b/models/post-author.js @@ -20,6 +20,7 @@ const postAuthorSchema = new mongoose.Schema({ required: [true, 'Description is required'], trim: true }, + // profile picture image link image: { type: String, trim: true diff --git a/models/progress-list.js b/models/progress-list.js index d8f7fc3..def6205 100644 --- a/models/progress-list.js +++ b/models/progress-list.js @@ -15,7 +15,7 @@ const progressListSchema = new mongoose.Schema({ default: 0 }, isGame: { - type: Boolean, /* true - is game list, false - is backend service */ + type: Boolean, /* true - is game, false - is backend service */ required: [true, 'isGame is required'] }, title: { diff --git a/passport.config.js b/passport.config.js index dfbbed9..782e09c 100644 --- a/passport.config.js +++ b/passport.config.js @@ -42,7 +42,7 @@ module.exports = (app) => { }); } )); - //Configuring app to have sessions + //Configuring app to have sessions, dont change since it would break everything passport.serializeUser(function(user, done) { done(null, user.id); }); diff --git a/routes/admin.js b/routes/admin.js index 0853375..1d9f9a0 100644 --- a/routes/admin.js +++ b/routes/admin.js @@ -1,7 +1,7 @@ /* admin.js - -file for handling admin panel routes +file for handling admin api. */ @@ -11,12 +11,14 @@ const passport = require('passport'); const moment = require('moment'); const apiHelper = require('../helpers/api'); const adminUserMiddleware = require('../middleware/admin-authentication'); + +// database models const adminUser = require('../models/admin-user'); const blogPost = require('../models/blog-post'); const postAuthor = require('../models/post-author'); const progressList = require('../models/progress-list'); -// display admin panel +// renders admin.hbs router.get('/admin', (req, res) => { res.render('admin'); }); @@ -27,18 +29,19 @@ router.get('/admin', (req, res) => { * signs admin user in * * post { -* username - username of admin account -* password - password of admin account +* username +* password * } * return { * code: http code -* success: boolean - true if login succesfull -* username: undefined | string - username if login was successfull +* success: boolean +* username: undefined | string - only if login was successfull * role: undefined | string - role of user if login was successfull * errors: Strings[messages] - not yet :( * } */ // TODO make login somehow display errors in correct format. +// middleware does the authentication work. this just returns a success router.post('/admin/api/v1/login', passport.authenticate('adminUserStrategy'), function (req, res) { apiHelper.sendApiReturn(res, { username: req.user.username, @@ -77,8 +80,8 @@ router.post('/admin/api/v1/register', adminUserMiddleware.adminAuthenticationReq password }); + // saving to database newUser.save().then(() => { - // successfull apiHelper.sendApiReturn(res, { username: req.user.username, role: req.user.role ? req.user.role : undefined @@ -108,6 +111,7 @@ router.post('/admin/api/v1/register', adminUserMiddleware.adminAuthenticationReq */ router.post('/admin/api/v1/removeadmin', adminUserMiddleware.adminAuthenticationRequired, (req, res) => { if (!req.body) { + // no post body apiHelper.sendApiGenericError(res); return; } @@ -137,11 +141,13 @@ router.get('/admin/api/v1/listadmins', adminUserMiddleware.adminAuthenticationRe // TODO format exception so it doesnt have a huge list of errors if (err) return apiHelper.sendApiError(res, 500, [err]); + // formats admin list and removes password hash const output = []; for (let i = 0, l = admins.length; i < l; i++) { admins[i].password = undefined; output.push(admins[i]); } + apiHelper.sendApiReturn(res, { admins: output }); @@ -216,7 +222,7 @@ router.post('/admin/api/v1/newpost', adminUserMiddleware.adminAuthenticationRequ meta: { author, category, - slug: title + slug: title // convert title to slug .trim() .replace(/\s/g, '-') .replace(/[^A-z0-9-]/g, '') @@ -224,8 +230,8 @@ router.post('/admin/api/v1/newpost', adminUserMiddleware.adminAuthenticationRequ } }); + // saving post to database newBlogPost.save().then((post) => { - // successfull apiHelper.sendApiReturn(res, { url: moment(post.meta.date, 'YYYY-MM-DD') + '/' + post.meta.slug }); @@ -269,6 +275,7 @@ router.post('/admin/api/v1/editpost', adminUserMiddleware.adminAuthenticationReq 'meta.category': category }, (err, post) => { if (err) return apiHelper.sendApiError(res, 500, [err]); + apiHelper.sendApiReturn(res, { url: moment(post.meta.date, 'YYYY-MM-DD') + '/' + post.meta.slug }); @@ -303,8 +310,8 @@ router.post('/admin/api/v1/newauthor', adminUserMiddleware.adminAuthenticationRe image }); + // saving author to database newAuthor.save().then((author) => { - // successfull apiHelper.sendApiReturn(res, { id: author.id }); @@ -339,6 +346,7 @@ router.post('/admin/api/v1/editauthor', adminUserMiddleware.adminAuthenticationR const { id, name, description, image } = req.body; + // updating author in database postAuthor.postAuthorModel.findByIdAndUpdate(id, { name, description, @@ -373,6 +381,7 @@ router.post('/admin/api/v1/newprogress', adminUserMiddleware.adminAuthentication if (!req.body) return apiHelper.sendApiGenericError(res); + // parses state and isGame to be valid const { title, description } = req.body; let { state } = req.body; let isGame = false; @@ -390,8 +399,8 @@ router.post('/admin/api/v1/newprogress', adminUserMiddleware.adminAuthentication state }); + // saving progress to database newProgress.save().then((progress) => { - // successfull apiHelper.sendApiReturn(res, { id: progress.id }); @@ -424,6 +433,7 @@ router.post('/admin/api/v1/editprogress', adminUserMiddleware.adminAuthenticatio if (!req.body) return apiHelper.sendApiGenericError(res); + // parsing state and isGame to be valid const { title, description, id } = req.body; let { state } = req.body; let isGame = false; @@ -434,6 +444,7 @@ router.post('/admin/api/v1/editprogress', adminUserMiddleware.adminAuthenticatio isGame = true; } + // updating progress in database progressList.progressListModel.findByIdAndUpdate(id, { title, description, @@ -448,7 +459,7 @@ router.post('/admin/api/v1/editprogress', adminUserMiddleware.adminAuthenticatio }); }); -// configure api 404 +// api 404 router.use('/admin/api', (req, res) => { apiHelper.sendApi404(res); }); diff --git a/routes/blog.js b/routes/blog.js index 273afe5..26ac65e 100644 --- a/routes/blog.js +++ b/routes/blog.js @@ -14,7 +14,7 @@ const postAuthorModel = require('../models/post-author').postAuthorModel; // display single blog post router.get('/news/:date/:title', (req, res) => { - // date format DD-MM-YYY + // date format YYYY-MM-DD if (/[0-9]{4}-[0-9]{2}-[0-9]{2}/.test(req.params.date) && /([a-z]|[0-9]|-)+/.test(req.params.title.toLowerCase())) { // params are correct format blogPostModel.getPost(new Date(req.params.date), req.params.title.toLowerCase(), (err, post) => { @@ -40,11 +40,13 @@ router.get('/news/:date/:title', (req, res) => { // display latest blogposts router.get('/news', (req, res) => { + // sort blogposts on date descending blogPostModel.find({}).sort({'meta.date': 'desc'}).exec(function(err, posts) { if (err || !posts) { return utilHelper.sendDefault404(res); } + // makes posts template ready const postCollection = []; for (let i = 0, l = posts.length; i < l; i++) { postCollection.push(posts[i].getBlogPostShortTemplateReady()); diff --git a/routes/contact.js b/routes/contact.js index 627e4df..ccafd45 100644 --- a/routes/contact.js +++ b/routes/contact.js @@ -35,13 +35,15 @@ router.get('/contact', (req, res) => { router.post('/api/v1/sendmessage', function (req, res) { if (!req.body) return apiHelper.sendApiGenericError(res); + const { email, subject, message } = req.body; if (email && subject && message && message.length < 2000) { - console.log('checks passed'); + // request body has everything const postData = JSON.stringify({ content: 'email: ' + email + ' \n subject: ' + subject + ' \n\n' + message }); + // request object const request = https.request({ hostname: config.contactWebhook.host, port: config.contactWebhook.port, @@ -53,14 +55,17 @@ router.post('/api/v1/sendmessage', function (req, res) { 'Content-Length': postData.length } }, () => { + // sends success apiHelper.sendApiReturn(res, {}); }); + // error handling request.on('error', (e) => { apiHelper.sendApiGenericError(res); console.log('request errored' + e); }); + // write post data to request request.write(postData); request.end(); } else { diff --git a/routes/progress.js b/routes/progress.js index 76ce1b9..860b5ee 100644 --- a/routes/progress.js +++ b/routes/progress.js @@ -18,6 +18,7 @@ router.get('/progress', (req, res) => { progressListModel.find({}, (err, progress) => { if (err) return utilHelper.sendDefault404(res); + // filtering games and backend const games = progress.filter(i => i.isGame); const backends = progress.filter(i => !i.isGame); diff --git a/server.js b/server.js index a934f94..f1ef203 100644 --- a/server.js +++ b/server.js @@ -45,6 +45,7 @@ app.use(session({ collection: 'sessions' }) })); +// setups up passportjs authentication passportconfig(app); // handlebars templating setup From 887f270b1d1724397a36c98512135328533ef126 Mon Sep 17 00:00:00 2001 From: mrjvs Date: Tue, 16 Oct 2018 16:21:08 +0200 Subject: [PATCH 13/13] update function names --- helpers/api.js | 4 +-- middleware/admin-authentication.js | 8 ++--- models/blog-post.js | 15 ++++------ models/post-author.js | 2 +- routes/admin.js | 48 +++++++++++++++--------------- routes/blog.js | 16 +++++----- routes/contact.js | 2 +- routes/progress.js | 4 +-- server.js | 2 +- 9 files changed, 49 insertions(+), 52 deletions(-) diff --git a/helpers/api.js b/helpers/api.js index 958b321..4b939c1 100644 --- a/helpers/api.js +++ b/helpers/api.js @@ -6,7 +6,7 @@ common api returns */ // use for any api return. it has basic layout used for every return. -function sendApiReturn(res, data, errors) { +function sendReturn(res, data, errors) { res.status(200).json( // combine 2 objects Object.assign({ @@ -59,7 +59,7 @@ function sendApiError(res, code, errors) { } module.exports = { - sendApiReturn, + sendReturn, sendApi404, sendApiGenericError, sendApiError, diff --git a/middleware/admin-authentication.js b/middleware/admin-authentication.js index 85f391d..777fb45 100644 --- a/middleware/admin-authentication.js +++ b/middleware/admin-authentication.js @@ -9,7 +9,7 @@ Middleware file for authentication checking const apiHelper = require('../helpers/api'); // middleware to use if admin authentication is required -function adminAuthenticationRequired(req, res, next) { +function adminAuthNeeded(req, res, next) { if (req.isAuthenticated() && req.user.role && req.user.role === 'admin') { return next(); } else { @@ -18,11 +18,11 @@ function adminAuthenticationRequired(req, res, next) { } // middleware to use if authentication is optional -function authenticationOptional(req, res, next) { +function authOptional(req, res, next) { return next(); } module.exports = { - adminAuthenticationRequired, - authenticationOptional + adminAuthNeeded, + authOptional }; \ No newline at end of file diff --git a/models/blog-post.js b/models/blog-post.js index c8ee610..fbf3804 100644 --- a/models/blog-post.js +++ b/models/blog-post.js @@ -56,10 +56,7 @@ const blogPostSchema = new mongoose.Schema({ } }); -blogPostSchema.methods.getContentAsHTML = function() { - return this.content; -}; -blogPostSchema.methods.getBlogPostTemplateReady = function(callback) { +blogPostSchema.methods.postTemplate = function(callback) { const self = this; postAuthor.findById(this.meta.author, function (err, author) { callback(err, { @@ -67,11 +64,11 @@ blogPostSchema.methods.getBlogPostTemplateReady = function(callback) { title: self.name, date: self.meta.date, category: self.meta.category, - author: author.getPostAuthorTemplateReady() + author: author.authorTemplate() }); }); }; -blogPostSchema.methods.getBlogPostShortTemplateReady = function() { +blogPostSchema.methods.postShortTemplate = function() { return { content: this.short, title: this.name, @@ -79,7 +76,7 @@ blogPostSchema.methods.getBlogPostShortTemplateReady = function() { }; }; -blogPostSchema.statics.convertMarkdownToHtml = function(markdown) { +blogPostSchema.statics.markdownToHtml = function(markdown) { return converter.makeHtml(markdown); }; blogPostSchema.statics.getPost = function(date, slug, callback) { @@ -89,12 +86,12 @@ blogPostSchema.statics.getPost = function(date, slug, callback) { }, callback); }; // not tested -blogPostSchema.statics.getLatestBlogPostShortTemplateReady = function(amount, callback) { +blogPostSchema.statics.latestPostsShortTemlate = function(amount, callback) { blogPostModel.find({}).sort({'meta.date': 'desc'}).exec(function(err, posts) { if (err) return callback(err); let out = []; for (let i = 0, l = posts.length; i < ( amount+1 < l ? amount+1 : l); i++) - out += posts[i].getBlogPostShortTemplateReady(); + out += posts[i].postShortTemplate(); callback(err, out); }); }; diff --git a/models/post-author.js b/models/post-author.js index 66904b5..4f7287a 100644 --- a/models/post-author.js +++ b/models/post-author.js @@ -27,7 +27,7 @@ const postAuthorSchema = new mongoose.Schema({ } }); -postAuthorSchema.methods.getPostAuthorTemplateReady = function() { +postAuthorSchema.methods.authorTemplate = function() { return { name: this.name, description: this.description, diff --git a/routes/admin.js b/routes/admin.js index 1d9f9a0..5332ca9 100644 --- a/routes/admin.js +++ b/routes/admin.js @@ -43,7 +43,7 @@ router.get('/admin', (req, res) => { // TODO make login somehow display errors in correct format. // middleware does the authentication work. this just returns a success router.post('/admin/api/v1/login', passport.authenticate('adminUserStrategy'), function (req, res) { - apiHelper.sendApiReturn(res, { + apiHelper.sendReturn(res, { username: req.user.username, role: req.user.role ? req.user.role : undefined }); @@ -67,7 +67,7 @@ router.post('/admin/api/v1/login', passport.authenticate('adminUserStrategy'), f * errors: Strings[messages] * } */ -router.post('/admin/api/v1/register', adminUserMiddleware.adminAuthenticationRequired, (req, res) => { +router.post('/admin/api/v1/register', adminUserMiddleware.adminAuthNeeded, (req, res) => { if (!req.body) { // no post body apiHelper.sendApiGenericError(res); @@ -82,7 +82,7 @@ router.post('/admin/api/v1/register', adminUserMiddleware.adminAuthenticationReq // saving to database newUser.save().then(() => { - apiHelper.sendApiReturn(res, { + apiHelper.sendReturn(res, { username: req.user.username, role: req.user.role ? req.user.role : undefined }); @@ -109,7 +109,7 @@ router.post('/admin/api/v1/register', adminUserMiddleware.adminAuthenticationReq * errors: Strings[messages] * } */ -router.post('/admin/api/v1/removeadmin', adminUserMiddleware.adminAuthenticationRequired, (req, res) => { +router.post('/admin/api/v1/removeadmin', adminUserMiddleware.adminAuthNeeded, (req, res) => { if (!req.body) { // no post body apiHelper.sendApiGenericError(res); @@ -120,7 +120,7 @@ router.post('/admin/api/v1/removeadmin', adminUserMiddleware.adminAuthentication adminUser.adminUserModel.findByIdAndDelete(id, (err) => { if (err) return apiHelper.sendApiError(res, 500, [err]); // successfull - apiHelper.sendApiReturn(res, {}); + apiHelper.sendReturn(res, {}); }); }); @@ -136,7 +136,7 @@ router.post('/admin/api/v1/removeadmin', adminUserMiddleware.adminAuthentication * errors: Strings[messages] * } */ -router.get('/admin/api/v1/listadmins', adminUserMiddleware.adminAuthenticationRequired, (req, res) => { +router.get('/admin/api/v1/listadmins', adminUserMiddleware.adminAuthNeeded, (req, res) => { adminUser.adminUserModel.find({}, (err, admins) => { // TODO format exception so it doesnt have a huge list of errors if (err) return apiHelper.sendApiError(res, 500, [err]); @@ -148,7 +148,7 @@ router.get('/admin/api/v1/listadmins', adminUserMiddleware.adminAuthenticationRe output.push(admins[i]); } - apiHelper.sendApiReturn(res, { + apiHelper.sendReturn(res, { admins: output }); }); @@ -167,8 +167,8 @@ router.get('/admin/api/v1/listadmins', adminUserMiddleware.adminAuthenticationRe * errors: Strings[messages] * } */ -router.get('/admin/api/v1/check', adminUserMiddleware.authenticationOptional, (req, res) => { - apiHelper.sendApiReturn(res, { +router.get('/admin/api/v1/check', adminUserMiddleware.authOptional, (req, res) => { + apiHelper.sendReturn(res, { isAuthed: req.user ? true : false, role: req.user ? (req.user.role ? req.user.role : undefined) : undefined }); @@ -185,9 +185,9 @@ router.get('/admin/api/v1/check', adminUserMiddleware.authenticationOptional, (r * errors: Strings[messages] * } */ -router.get('/admin/api/v1/logout', adminUserMiddleware.adminAuthenticationRequired, (req, res) => { +router.get('/admin/api/v1/logout', adminUserMiddleware.adminAuthNeeded, (req, res) => { req.logout(); - apiHelper.sendApiReturn(res, {}); + apiHelper.sendReturn(res, {}); }); /* @@ -210,13 +210,13 @@ router.get('/admin/api/v1/logout', adminUserMiddleware.adminAuthenticationRequir * errors: Strings[messages] * } */ -router.post('/admin/api/v1/newpost', adminUserMiddleware.adminAuthenticationRequired, function (req, res) { +router.post('/admin/api/v1/newpost', adminUserMiddleware.adminAuthNeeded, function (req, res) { if (!req.body) return apiHelper.sendApiGenericError(res); const { content, title, author, category, short } = req.body; const newBlogPost = new blogPost.blogPostModel({ - content: blogPost.blogPostModel.convertMarkdownToHtml(content), + content: blogPost.blogPostModel.markdownToHtml(content), name: title, short, meta: { @@ -232,7 +232,7 @@ router.post('/admin/api/v1/newpost', adminUserMiddleware.adminAuthenticationRequ // saving post to database newBlogPost.save().then((post) => { - apiHelper.sendApiReturn(res, { + apiHelper.sendReturn(res, { url: moment(post.meta.date, 'YYYY-MM-DD') + '/' + post.meta.slug }); }).catch((rejection) => { @@ -262,7 +262,7 @@ router.post('/admin/api/v1/newpost', adminUserMiddleware.adminAuthenticationRequ * errors: Strings[messages] * } */ -router.post('/admin/api/v1/editpost', adminUserMiddleware.adminAuthenticationRequired, function (req, res) { +router.post('/admin/api/v1/editpost', adminUserMiddleware.adminAuthNeeded, function (req, res) { if (!req.body) return apiHelper.sendApiGenericError(res); @@ -276,7 +276,7 @@ router.post('/admin/api/v1/editpost', adminUserMiddleware.adminAuthenticationReq }, (err, post) => { if (err) return apiHelper.sendApiError(res, 500, [err]); - apiHelper.sendApiReturn(res, { + apiHelper.sendReturn(res, { url: moment(post.meta.date, 'YYYY-MM-DD') + '/' + post.meta.slug }); }); @@ -299,7 +299,7 @@ router.post('/admin/api/v1/editpost', adminUserMiddleware.adminAuthenticationReq * errors: Strings[messages] * } */ -router.post('/admin/api/v1/newauthor', adminUserMiddleware.adminAuthenticationRequired, function (req, res) { +router.post('/admin/api/v1/newauthor', adminUserMiddleware.adminAuthNeeded, function (req, res) { if (!req.body) return apiHelper.sendApiGenericError(res); @@ -312,7 +312,7 @@ router.post('/admin/api/v1/newauthor', adminUserMiddleware.adminAuthenticationRe // saving author to database newAuthor.save().then((author) => { - apiHelper.sendApiReturn(res, { + apiHelper.sendReturn(res, { id: author.id }); }).catch((rejection) => { @@ -340,7 +340,7 @@ router.post('/admin/api/v1/newauthor', adminUserMiddleware.adminAuthenticationRe * errors: Strings[messages] * } */ -router.post('/admin/api/v1/editauthor', adminUserMiddleware.adminAuthenticationRequired, function (req, res) { +router.post('/admin/api/v1/editauthor', adminUserMiddleware.adminAuthNeeded, function (req, res) { if (!req.body) return apiHelper.sendApiGenericError(res); @@ -354,7 +354,7 @@ router.post('/admin/api/v1/editauthor', adminUserMiddleware.adminAuthenticationR }, (err, author) => { // TODO format exception so it doesnt have a huge list of errors if (err) return apiHelper.sendApiError(res, 500, [err]); - apiHelper.sendApiReturn(res, { + apiHelper.sendReturn(res, { id: author.id }); }); @@ -377,7 +377,7 @@ router.post('/admin/api/v1/editauthor', adminUserMiddleware.adminAuthenticationR * errors: Strings[messages] * } */ -router.post('/admin/api/v1/newprogress', adminUserMiddleware.adminAuthenticationRequired, function (req, res) { +router.post('/admin/api/v1/newprogress', adminUserMiddleware.adminAuthNeeded, function (req, res) { if (!req.body) return apiHelper.sendApiGenericError(res); @@ -401,7 +401,7 @@ router.post('/admin/api/v1/newprogress', adminUserMiddleware.adminAuthentication // saving progress to database newProgress.save().then((progress) => { - apiHelper.sendApiReturn(res, { + apiHelper.sendReturn(res, { id: progress.id }); }).catch((rejection) => { @@ -429,7 +429,7 @@ router.post('/admin/api/v1/newprogress', adminUserMiddleware.adminAuthentication * errors: Strings[messages] * } */ -router.post('/admin/api/v1/editprogress', adminUserMiddleware.adminAuthenticationRequired, function (req, res) { +router.post('/admin/api/v1/editprogress', adminUserMiddleware.adminAuthNeeded, function (req, res) { if (!req.body) return apiHelper.sendApiGenericError(res); @@ -453,7 +453,7 @@ router.post('/admin/api/v1/editprogress', adminUserMiddleware.adminAuthenticatio }, (err, progress) => { // TODO format exception so it doesnt have a huge list of errors if (err) return apiHelper.sendApiError(res, 500, [err]); - apiHelper.sendApiReturn(res, { + apiHelper.sendReturn(res, { id: progress.id }); }); diff --git a/routes/blog.js b/routes/blog.js index 26ac65e..7284e92 100644 --- a/routes/blog.js +++ b/routes/blog.js @@ -21,12 +21,12 @@ router.get('/news/:date/:title', (req, res) => { // error exists or no post exists with the date and name if (err || !post) { console.log('error: ' + err + ' and post: ' + post); - return utilHelper.sendDefault404(res); + return utilHelper.send404(res); } // render blogpost - post.getBlogPostTemplateReady((err, postTemplate) => { - if (err) return utilHelper.sendDefault404(res); + post.postTemplate((err, postTemplate) => { + if (err) return utilHelper.send404(res); res.render('post', { post: postTemplate }); @@ -34,7 +34,7 @@ router.get('/news/:date/:title', (req, res) => { }); } else { // params are incorrect - utilHelper.sendDefault404(res); + utilHelper.send404(res); } }); @@ -43,13 +43,13 @@ router.get('/news', (req, res) => { // sort blogposts on date descending blogPostModel.find({}).sort({'meta.date': 'desc'}).exec(function(err, posts) { if (err || !posts) { - return utilHelper.sendDefault404(res); + return utilHelper.send404(res); } // makes posts template ready const postCollection = []; for (let i = 0, l = posts.length; i < l; i++) { - postCollection.push(posts[i].getBlogPostShortTemplateReady()); + postCollection.push(posts[i].postShortTemplate()); } res.render('post-collection', { @@ -74,7 +74,7 @@ router.get('/api/v1/listauthors', function (req, res) { postAuthorModel.find({}, (err, authors) => { // TODO format exception so it doesnt have a huge list of errors if (err) return apiHelper.sendApiError(res, 500, [err]); - apiHelper.sendApiReturn(res, { + apiHelper.sendReturn(res, { authorList: authors }); }); @@ -96,7 +96,7 @@ router.get('/api/v1/listblog', function (req, res) { blogPostModel.find({}, (err, posts) => { // TODO format exception so it doesnt have a huge list of errors if (err) return apiHelper.sendApiError(res, 500, [err]); - apiHelper.sendApiReturn(res, { + apiHelper.sendReturn(res, { postList: posts }); }); diff --git a/routes/contact.js b/routes/contact.js index ccafd45..26c8bd3 100644 --- a/routes/contact.js +++ b/routes/contact.js @@ -56,7 +56,7 @@ router.post('/api/v1/sendmessage', function (req, res) { } }, () => { // sends success - apiHelper.sendApiReturn(res, {}); + apiHelper.sendReturn(res, {}); }); // error handling diff --git a/routes/progress.js b/routes/progress.js index 860b5ee..254ae6e 100644 --- a/routes/progress.js +++ b/routes/progress.js @@ -16,7 +16,7 @@ const progressListModel = require('../models/progress-list').progressListModel; router.get('/progress', (req, res) => { progressListModel.find({}, (err, progress) => { - if (err) return utilHelper.sendDefault404(res); + if (err) return utilHelper.send404(res); // filtering games and backend const games = progress.filter(i => i.isGame); @@ -46,7 +46,7 @@ router.get('/api/v1/listprogress', function (req, res) { progressListModel.find({}, (err, progress) => { // TODO format exception so it doesnt have a huge list of errors if (err) return apiHelper.sendApiError(res, 500, [err]); - apiHelper.sendApiReturn(res, { + apiHelper.sendReturn(res, { progressList: progress }); }); diff --git a/server.js b/server.js index f1ef203..416e809 100644 --- a/server.js +++ b/server.js @@ -74,7 +74,7 @@ app.use('/', locations.posts); app.use('/', locations.admin); app.use('/', locations.progress); app.use((req, res) => { - utilHelper.sendDefault404(res); + utilHelper.send404(res); }); // TODO improve error handling