Template Engine Upgradepull/46/head
@ -0,0 +1,129 @@ | |||||
/** | |||||
* File which deals with adding and removing downloads from | |||||
* the admin section of the website. | |||||
* | |||||
* @author Jeffery Russell 6-30-18 | |||||
*/ | |||||
/** Whiskers template file */ | |||||
const TEMPLATE_FILE = "admin/adminDownloads.html"; | |||||
const includes = require('../includes/includes.js'); | |||||
//updates db | |||||
const sql = require('../utils/sql'); | |||||
//parses post data | |||||
const qs = require('querystring'); | |||||
/** | |||||
* Processes post requests from the addDownload form | |||||
* | |||||
* @param postData | |||||
* @returns {*|Promise} | |||||
*/ | |||||
const addDownloadPostData = function(postData) | |||||
{ | |||||
return new Promise(function(resolve, reject) | |||||
{ | |||||
const post = qs.parse(postData); | |||||
if(post.add_download) | |||||
{ | |||||
sql.addDownload(post.add_download_name, post.add_download_file) | |||||
.then(function() | |||||
{ | |||||
resolve(); | |||||
}).catch(function(error) | |||||
{ | |||||
reject(error); | |||||
}) | |||||
} | |||||
else | |||||
{ | |||||
resolve(); | |||||
} | |||||
}); | |||||
}; | |||||
/** | |||||
* Removes a download if requested by the | |||||
* post data from an admin. | |||||
*/ | |||||
const removeDownloads = function(postData) | |||||
{ | |||||
return new Promise(function(resolve, reject) | |||||
{ | |||||
const post = qs.parse(postData); | |||||
if(post.delete_download) | |||||
{ | |||||
sql.removeDownload(post.delete_download).then(function() | |||||
{ | |||||
resolve(); | |||||
}).catch(function(err) | |||||
{ | |||||
reject(err); | |||||
}); | |||||
} | |||||
else | |||||
{ | |||||
resolve(); | |||||
} | |||||
}); | |||||
}; | |||||
/** | |||||
* Fetches the download items in the database so that | |||||
* the template engine can use it to display them in | |||||
* a table. | |||||
* | |||||
* @param templateContext-- context item used by whiskers | |||||
* @returns {Promise} | |||||
*/ | |||||
const displayDownloads = function(templateContext) | |||||
{ | |||||
return new Promise(function(resolve, reject) | |||||
{ | |||||
sql.getAllDownloads().then(function(downloads) | |||||
{ | |||||
templateContext.downloads = downloads; | |||||
resolve(); | |||||
}).catch(function(error) | |||||
{ | |||||
reject(error); | |||||
}); | |||||
}); | |||||
}; | |||||
module.exports= | |||||
{ | |||||
/** Fetches context information for the template and handles | |||||
* post data for the downloads. | |||||
* | |||||
* @param postData posted by user | |||||
* @param templateContext json object used as the template context | |||||
* @returns {Promise} renders the template used for this page | |||||
*/ | |||||
main: function(postData, templateContext) | |||||
{ | |||||
return new Promise(function(resolve, reject) | |||||
{ | |||||
Promise.all([includes.fetchTemplate(TEMPLATE_FILE), | |||||
addDownloadPostData(postData), | |||||
removeDownloads(postData), | |||||
displayDownloads(templateContext)]).then(function(template) | |||||
{ | |||||
resolve(template[0]); | |||||
}).catch(function(error) | |||||
{ | |||||
console.log("error in add downloads.js"); | |||||
reject(error); | |||||
}); | |||||
}); | |||||
} | |||||
}; |
@ -0,0 +1,138 @@ | |||||
const TEMPLATE_FILE = "admin/adminHome.html"; | |||||
const includes = require('../includes/includes.js'); | |||||
const sql = require('../utils/sql'); | |||||
const qs = require('querystring'); | |||||
/** | |||||
* Checks for post data regarding adding a new category. | |||||
* If a post is made with add_category, it parses the url-- replaces spaces | |||||
* with dashes -- and calls a insert method on the database | |||||
* | |||||
* @param postData | |||||
* @return {*|Promise} | |||||
*/ | |||||
const processPostAddCategory = function(postData) | |||||
{ | |||||
return new Promise(function(resolve, reject) | |||||
{ | |||||
const post = qs.parse(postData); | |||||
if(post.add_category) | |||||
{ | |||||
const url = post.add_category.split(" ").join("-").toLowerCase(); | |||||
const q = "insert into categories (name, url) values " + | |||||
"('" + post.add_category + "','" + url + "')"; | |||||
if(sql.insert(q) != 0) | |||||
{ | |||||
console.log("category added"); | |||||
} | |||||
else | |||||
{ | |||||
console.log("error adding category"); | |||||
} | |||||
} | |||||
resolve(""); | |||||
}); | |||||
}; | |||||
/** | |||||
* Displays all the categories in the database | |||||
* @return {*|Promise} | |||||
*/ | |||||
const appendCategoriesToTemplate = function(templateContext) | |||||
{ | |||||
return new Promise(function(resolve, reject) | |||||
{ | |||||
sql.getCategories().then(function(categories) | |||||
{ | |||||
templateContext.categories = categories; | |||||
resolve(); | |||||
}).catch(function(error) | |||||
{ | |||||
reject(error); | |||||
}) | |||||
}); | |||||
}; | |||||
/** | |||||
* | |||||
* @param postData | |||||
* @return {*|Promise} | |||||
*/ | |||||
const processPost = function(postData) | |||||
{ | |||||
return new Promise(function(resolve, reject) | |||||
{ | |||||
var post = qs.parse(postData); | |||||
if(post.add_post_name) | |||||
{ | |||||
var urls = post.add_post_name; | |||||
urls = urls.split(" ").join("-"); | |||||
urls =urls.toLowerCase(); | |||||
var q = "insert into blog (category_id, picture_url, published, name, url) values "; | |||||
q += "('" + post.add_post_category + "', '" + post.add_post_picture + | |||||
"', '" + post.add_post_date + "', '" + post.add_post_name + "', '" + urls + "')"; | |||||
sql.insert(q).then(function() | |||||
{ | |||||
var map = require('../utils/generateSiteMap'); | |||||
map.main(); | |||||
resolve(""); | |||||
}).catch(function(error) | |||||
{ | |||||
reject(error); | |||||
}) | |||||
} | |||||
else if(post.clear_cache) | |||||
{ | |||||
require("../sites/blog.js").clearCache(); | |||||
require("../includes/includes.js").clearCache(); | |||||
} | |||||
else if(post.git_pull) | |||||
{ | |||||
const execSync = require('child_process').execSync; | |||||
code = execSync('git pull') | |||||
} | |||||
else | |||||
{ | |||||
resolve(""); | |||||
} | |||||
}); | |||||
}; | |||||
module.exports= | |||||
{ | |||||
/** | |||||
* | |||||
* @param postData posted by user | |||||
* @param templateContext json object used as the template context | |||||
* @returns {Promise} renders the template used for this page | |||||
*/ | |||||
main: function(postData, templateContext) | |||||
{ | |||||
console.log("called"); | |||||
return new Promise(function(resolve, reject) | |||||
{ | |||||
Promise.all([includes.fetchTemplate(TEMPLATE_FILE), | |||||
processPostAddCategory(postData), | |||||
appendCategoriesToTemplate(templateContext), | |||||
processPost(postData)]) | |||||
.then(function(template) | |||||
{ | |||||
resolve(template[0]); | |||||
}).catch(function(error) | |||||
{ | |||||
console.log("error in add downloads.js"); | |||||
reject(error); | |||||
}); | |||||
}); | |||||
} | |||||
}; |
@ -1,15 +0,0 @@ | |||||
<div class="blogPost"> | |||||
<h1 class="text-center">Add Category</h1> | |||||
<form action="/admin" method ="post" class="p-2"> | |||||
<div class="form-group"> | |||||
<input class="form-control" type="text" name="add_category" required> | |||||
<label>Category</label> | |||||
</div> | |||||
<div class="text-center"> | |||||
<input type="submit" name="submit" value="Add" | |||||
class="btn btn-lg btn-secondary"/> | |||||
</div> | |||||
</form> | |||||
</div> | |||||
<br> |
@ -1,98 +0,0 @@ | |||||
//file io | |||||
const utils = require('../../utils/utils.js'); | |||||
//update db | |||||
const sql = require('../../utils/sql'); | |||||
//parse post data | |||||
const qs = require('querystring'); | |||||
/** | |||||
* Displays all the categories in the database | |||||
* @return {*|Promise} | |||||
*/ | |||||
const printCategories = function() | |||||
{ | |||||
var html = "<div class=\"blogPost\">" + | |||||
"<h1 class=\"text-center\">Categories</h1>" + | |||||
"<div class=\"\"><table class=\"table table-striped\">" + | |||||
"<thead class=\"thead-dark\">" + | |||||
"<tr>" + | |||||
"<td>Name</td><td>URL</td><td>Edit</td>" + | |||||
"</tr></thead><tbody>"; | |||||
return new Promise(function(resolve, reject) | |||||
{ | |||||
sql.getCategories().then(function(categories) | |||||
{ | |||||
categories.forEach(function(c) | |||||
{ | |||||
html +="<tr>" + | |||||
"<td>" + c.name + "</td>" + | |||||
"<td>" + c.url + "</td>" + | |||||
"<td>" + c.category_id + "</td>" + | |||||
"</tr>"; | |||||
}); | |||||
resolve(html + "</tbody></table></div></div>"); | |||||
}).catch(function(error) | |||||
{ | |||||
reject(error); | |||||
}) | |||||
}); | |||||
}; | |||||
/** | |||||
* Checks for post data regarding adding a new category. | |||||
* If a post is made with add_category, it parses the url-- replaces spaces | |||||
* with dashes -- and calls a insert method on the database | |||||
* | |||||
* @param postData | |||||
* @return {*|Promise} | |||||
*/ | |||||
const processPost = function(postData) | |||||
{ | |||||
return new Promise(function(resolve, reject) | |||||
{ | |||||
const post = qs.parse(postData); | |||||
if(post.add_category) | |||||
{ | |||||
const url = post.add_category.split(" ").join("-").toLowerCase(); | |||||
const q = "insert into categories (name, url) values " + | |||||
"('" + post.add_category + "','" + url + "')"; | |||||
if(sql.insert(q) != 0) | |||||
{ | |||||
console.log("category added"); | |||||
} | |||||
else | |||||
{ | |||||
console.log("error adding category"); | |||||
} | |||||
} | |||||
resolve(""); | |||||
}); | |||||
}; | |||||
module.exports= | |||||
{ | |||||
main: function(postData) | |||||
{ | |||||
return new Promise(function(resolve, reject) | |||||
{ | |||||
Promise.all([utils.include("./admin/category/addCategory.html"), | |||||
printCategories(), | |||||
processPost(postData)]).then(function(html) | |||||
{ | |||||
resolve("<div class=\"col-md-6\">" + | |||||
html.join('') + | |||||
"</div></div>"); | |||||
}).catch(function(error) | |||||
{ | |||||
console.log("error in addCategory.js"); | |||||
reject(error); | |||||
}) | |||||
}); | |||||
} | |||||
}; |
@ -1,19 +0,0 @@ | |||||
<div class="blogPost"> | |||||
<h1 class="text-center">Add Download</h1> | |||||
<form action="/admin" method ="post" class="p-2"> | |||||
<div class="form-group"> | |||||
<input class="form-control" type="text" name="add_download_name" required> | |||||
<label>Download Name</label> | |||||
</div> | |||||
<div class="form-group"> | |||||
<input class="form-control" type="text" name="add_download_file" required> | |||||
<label>File name</label> | |||||
</div> | |||||
<div class="text-center"> | |||||
<input type="submit" name="add_download" value="Add Download" | |||||
class="btn btn-lg btn-secondary"/> | |||||
</div> | |||||
</form> | |||||
</div> | |||||
<br> |
@ -1,191 +0,0 @@ | |||||
/** | |||||
* File which deals with adding and removing downloads from | |||||
* the admin section of the website. | |||||
* | |||||
* @author Jeffery Russell 6-30-18 | |||||
*/ | |||||
//file IO | |||||
const utils = require('../../utils/utils.js'); | |||||
//updates db | |||||
const sql = require('../../utils/sql'); | |||||
//parses post data | |||||
const qs = require('querystring'); | |||||
/** | |||||
* Processes post requests from the addDownload form | |||||
* | |||||
* @param postData | |||||
* @returns {*|Promise} | |||||
*/ | |||||
const addDownloadPostData = function(postData) | |||||
{ | |||||
return new Promise(function(resolve, reject) | |||||
{ | |||||
const post = qs.parse(postData); | |||||
if(post.add_download) | |||||
{ | |||||
sql.addDownload(post.add_download_name, post.add_download_file) | |||||
.then(function() | |||||
{ | |||||
resolve(""); | |||||
}).catch(function(error) | |||||
{ | |||||
reject(error); | |||||
}) | |||||
} | |||||
else | |||||
{ | |||||
resolve(""); | |||||
} | |||||
}); | |||||
}; | |||||
/** | |||||
* Displays the addDownload form the the user | |||||
* | |||||
* @param postData | |||||
* @returns {*|Promise} | |||||
*/ | |||||
const addDownload = function(postData) | |||||
{ | |||||
return new Promise(function(resolve, reject) | |||||
{ | |||||
Promise.all([addDownloadPostData(postData), | |||||
utils.include("./admin/downloads/addDownload.html")]).then(function(html) | |||||
{ | |||||
resolve("<div class=\"col-md-6\">" + html.join('') + "</div>"); | |||||
}).catch(function(error) | |||||
{ | |||||
reject(error); | |||||
}) | |||||
}); | |||||
}; | |||||
/** | |||||
* Handel form requests from the downloads table | |||||
* | |||||
* @param postData | |||||
* @returns {*|Promise} | |||||
*/ | |||||
const displayDownloadsPostData = function(postData) | |||||
{ | |||||
return new Promise(function(resolve, reject) | |||||
{ | |||||
const post = qs.parse(postData); | |||||
if(post.delete_download) | |||||
{ | |||||
sql.removeDownload(post.delete_download).then(function() | |||||
{ | |||||
resolve(postData); | |||||
}).catch(function(err) | |||||
{ | |||||
reject(err); | |||||
}); | |||||
} | |||||
else | |||||
{ | |||||
resolve(postData); | |||||
} | |||||
}); | |||||
}; | |||||
/** | |||||
* Renders a single download row in the downloads table | |||||
* | |||||
* @param download | |||||
* @returns {*|Promise} | |||||
*/ | |||||
const renderDownloadRow = function(download) | |||||
{ | |||||
return "<tr>" + | |||||
"<td>" + download.name + "</td>" + | |||||
"<td>" + download.file + "</td>" + | |||||
"<td>" + download.download_count + "</td>" + | |||||
"<td><form action=\"/admin\" method =\"post\" >\n" + | |||||
" <input type=\"submit\" name=\"submit\" value=\"Delete\"\n" + | |||||
" class=\"btn btn-secondary\"/>\n" + | |||||
"<input type='hidden' name='delete_download' value='" + | |||||
download.download_id + "'/>"+ | |||||
"</form></td>" + | |||||
"</tr>"; | |||||
}; | |||||
/** | |||||
* Displays all the download information in a table | |||||
* @param postData | |||||
* @returns {*|Promise} | |||||
*/ | |||||
const displayDownloads = function(postData) | |||||
{ | |||||
var html = "<div class=\"col-md-6\">"; | |||||
return new Promise(function(resolve, reject) | |||||
{ | |||||
displayDownloadsPostData(postData).then(function() | |||||
{ | |||||
html += "<div class='blogPost'>" + | |||||
"<h1 class=\"text-center\">Downloads</h1>" + | |||||
"<div class=\"\"><table class=\"table table-striped\">" + | |||||
"<thead class=\"thead-dark\"><tr>" + | |||||
"<td>Download Name</td><td>File</td>" + | |||||
"<td>Download Count</td><td>Delete</td>" + | |||||
"</tr></thead><tbody>"; | |||||
sql.getAllDownloads().then(function(downloads) | |||||
{ | |||||
var downloadPromises = []; | |||||
downloads.forEach(function(download) | |||||
{ | |||||
downloadPromises.push(renderDownloadRow(download)); | |||||
}); | |||||
Promise.all(downloadPromises).then(function(htmls) | |||||
{ | |||||
const htmlafter = "</tbody></table></div></div><br>" + | |||||
"</div>"; | |||||
resolve(html + htmls.join('') + htmlafter); | |||||
}); | |||||
}).catch(function(error) | |||||
{ | |||||
reject(error); | |||||
}); | |||||
}); | |||||
}); | |||||
}; | |||||
module.exports= | |||||
{ | |||||
/** | |||||
* Renders tha download section of the admin page | |||||
* | |||||
* @param postData | |||||
* @returns {Promise} | |||||
*/ | |||||
main: function(postData) | |||||
{ | |||||
return new Promise(function(resolve, reject) | |||||
{ | |||||
Promise.all([addDownload(postData), | |||||
displayDownloads(postData)]).then(function(html) | |||||
{ | |||||
resolve("<div class=\"row\">" + html.join('') + "</div>"); | |||||
}).catch(function(error) | |||||
{ | |||||
console.log("error in add downloads.js"); | |||||
reject(error); | |||||
}); | |||||
}); | |||||
} | |||||
}; |
@ -1,28 +0,0 @@ | |||||
<div class="col-md-8"> | |||||
<div class="blogPost"> | |||||
<div class="text-center"> | |||||
<h2>Login</h2> | |||||
</div> | |||||
<form action="/admin" method ="post" class="p-2"> | |||||
<div class="form-group"> | |||||
<label for="username1">User Name</label> | |||||
<input class="form-control" type="test" id="username1" name="username" placeholder="Enter username" required> | |||||
</div> | |||||
<div class="form-group"> | |||||
<label for="password1">Password</label> | |||||
<input class="form-control" type="password" name="password" id="password1" placeholder="Password" required> | |||||
</div> | |||||
<div class="text-center"> | |||||
<button class="btn btn-lg btn-secondary">Login</button> | |||||
</div> | |||||
<br> | |||||
</form> | |||||
<!-- | |||||
/\_/\ ___ | |||||
= o_o =_______ \ \ | |||||
__^ __( \.__) ) | |||||
(@)<_____>__(_____)____/ | |||||
--> | |||||
</div> | |||||
</div> |
@ -0,0 +1,103 @@ | |||||
/** Whiskers template file | |||||
* this has stuff for both editing blog and viewing a list of blog*/ | |||||
const TEMPLATE_FILE = "admin/adminPosts.html"; | |||||
const includes = require('../includes/includes.js'); | |||||
const sql = require('../utils/sql'); | |||||
//parses the post data | |||||
const qs = require('querystring'); | |||||
/** | |||||
* Detects if the post data came from the edit form in blog table or edit post | |||||
* in the edit post form. | |||||
* | |||||
* @param postData | |||||
* @param renderContext | |||||
* @returns {Promise} | |||||
*/ | |||||
const processPostData = function(postData, renderContext) | |||||
{ | |||||
return new Promise(function(resolve, reject) | |||||
{ | |||||
var postParsed = qs.parse(postData); | |||||
if(postParsed.edit_post) | |||||
{ | |||||
renderContext.editPost = true; | |||||
sql.getPostById(postParsed.edit_post).then(function(post) | |||||
{ | |||||
post.published = post.published.toISOString().split('T')[0]; | |||||
renderContext.post = post; | |||||
resolve(); | |||||
}); | |||||
} | |||||
else if(postParsed.edit_post_2) | |||||
{ | |||||
sql.editPost(postParsed).then(function() | |||||
{ | |||||
resolve(); | |||||
}).catch(function(error) | |||||
{ | |||||
reject(error); | |||||
}); | |||||
} | |||||
else | |||||
{ | |||||
resolve(); | |||||
} | |||||
}); | |||||
}; | |||||
/** | |||||
* Grabs and appends the list of blog from the SQL database to | |||||
* the template context for the template renderer. | |||||
* | |||||
* @param templateContext | |||||
* @returns {Promise} | |||||
*/ | |||||
const fetchPostsInformation = function(templateContext) | |||||
{ | |||||
return new Promise(function(resolve, reject) | |||||
{ | |||||
sql.getAllPosts().then(function(posts) | |||||
{ | |||||
templateContext.posts = posts; | |||||
resolve(); | |||||
}).catch(function(error) | |||||
{ | |||||
reject(error); | |||||
}) | |||||
}); | |||||
}; | |||||
module.exports= | |||||
{ | |||||
/** | |||||
* Fetches context information for the admin blog page and handles post | |||||
* data sent regarding editing blog. | |||||
* | |||||
* @param postData posted by user | |||||
* @param templateContext json object used as the template context | |||||
* @returns {Promise} renders the template used for this page | |||||
*/ | |||||
main: function(postData, templateContext) | |||||
{ | |||||
return new Promise(function(resolve, reject) | |||||
{ | |||||
Promise.all([includes.fetchTemplate(TEMPLATE_FILE), | |||||
processPostData(postData, templateContext), | |||||
fetchPostsInformation(templateContext)]).then(function(template) | |||||
{ | |||||
resolve(template[0]); | |||||
}).catch(function(error) | |||||
{ | |||||
console.log("error in add admin blog.js"); | |||||
reject(error); | |||||
}); | |||||
}); | |||||
} | |||||
}; |
@ -1,182 +0,0 @@ | |||||
/** | |||||
* File which renders the edit form for the posts and processes | |||||
* the post data generated by edit forms. | |||||
* | |||||
* @type {Promise|*} | |||||
*/ | |||||
//parses the post data | |||||
const qs = require('querystring'); | |||||
//updates db | |||||
const sql = require('../../utils/sql'); | |||||
/** | |||||
* Displays a single row in the posts view | |||||
* | |||||
* @param post | |||||
*/ | |||||
const renderPostRow = function(post) | |||||
{ | |||||
return "<tr>" + | |||||
"<td>" + post.category_id + "</td>" + | |||||
"<td>" + post.name + "</td>" + | |||||
"<td>" + post.picture_url + "</td>" + | |||||
"<td>" + post.published + "</td>" + | |||||
"<td><form action=\"/admin\" method =\"post\" >\n" + | |||||
"<input type=\"submit\" name=\"submit\" value=\"Edit\"\n" + | |||||
" class=\"btn btn-secondary\"/>\n" + | |||||
"<input type='hidden' name='edit_post' value='" + post.post_id + "'/>"+ | |||||
"</form></td>" + | |||||
"</tr>"; | |||||
}; | |||||
/** | |||||
* Displays all the posts in a table | |||||
*/ | |||||
const postsTable = function() | |||||
{ | |||||
const html = "<div class='blogPost p-2'>" + | |||||
"<h1 class=\"text-center\">Posts</h1>" + | |||||
"<div class=\"\"><table class=\"table table-striped\">" + | |||||
"<thead class=\"thead-dark\"><tr>" + | |||||
"<td>Category #</td><td>Name</td><td>Header Picture</td><td>Date</td><td>Edit</td>" + | |||||
"</tr></thead><tbody>"; | |||||
return new Promise(function(resolve, reject) | |||||
{ | |||||
sql.getAllPosts().then(function(posts) | |||||
{ | |||||
var postPromises = []; | |||||
posts.forEach(function(post) | |||||
{ | |||||
postPromises.push(renderPostRow(post)); | |||||
}); | |||||
Promise.all(postPromises).then(function(htmls) | |||||
{ | |||||
resolve(html + htmls.join('') + "</tbody></table></div></div><br>"); | |||||
}).catch(function(error) | |||||
{ | |||||
reject(error); | |||||
}); | |||||
}).catch(function(error) | |||||
{ | |||||
reject(error); | |||||
}) | |||||
}); | |||||
}; | |||||
/** | |||||
* Displays the edit form for edit posts | |||||
* | |||||
* @param post_id | |||||
*/ | |||||
const displayRenderForm = function(post_id) | |||||
{ | |||||
return new Promise(function(resolve, reject) | |||||
{ | |||||
sql.getPostById(post_id).then(function(post) | |||||
{ | |||||
const html = "<div class='blogPost'>"+ | |||||
"<h1 class=\"text-center\">Edit Post</h1>"+ | |||||
"<form action=\"/admin\" method =\"post\" >"+ | |||||
" <div class=\"form-group\">\n" + | |||||
" <input class=\"form-control\" type=\"text\" name=\"edit_cat_num\" value='" + post.category_id + "' required>\n" + | |||||
" <label class=\"w3-label w3-validate\">Category Number</label>\n" + | |||||
" </div>"+ | |||||
" <div class=\"form-group\">\n" + | |||||
" <input class=\"form-control\" type=\"text\" name=\"edit_name_new\" value='" + post.name + "' required>\n" + | |||||
" <label class=\"w3-label w3-validate\">Post Title</label>\n" + | |||||
" </div>"+ | |||||
" <div class=\"form-group\">\n" + | |||||
" <input class=\"form-control\" type=\"text\" name=\"edit_pic\" value='" + post.picture_url + "' required>\n" + | |||||
" <label class=\"w3-label w3-validate\">Picture URL</label>\n" + | |||||
" </div>"+ | |||||
" <div class=\"form-group\">\n" + | |||||
" <input class=\"form-control\" type=\"date\" name=\"edit_date\" value='" + post.published.toISOString().split('T')[0] + "' required>\n" + | |||||
" <label class=\"w3-label w3-validate\">Published Date</label>\n" + | |||||
" </div>"+ | |||||
" <div><input type=\"submit\" name=\"submit\" value=\"Edit\"\n" + | |||||
" class=\"btn btn-lg btn-secondary\"/></div>"+ | |||||
"<input type='hidden' name='edit_post_2' value='" + post_id + "'/>"+ | |||||
"</form>"+ | |||||
"</div><br>"; | |||||
resolve(html); | |||||
}).catch(function(error) | |||||
{ | |||||
reject(error); | |||||
}); | |||||
}); | |||||
}; | |||||
/** | |||||
* Detects if the post data came from the edit form in posts table or edit post | |||||
* in the edit post form. Based on this, this function will call one of two functions | |||||
* | |||||
* @param postData | |||||
*/ | |||||
const processPost = function(postData) | |||||
{ | |||||
return new Promise(function(resolve, reject) | |||||
{ | |||||
var postParsed = qs.parse(postData); | |||||
if(postParsed.edit_post) | |||||
{ | |||||
//display edit form | |||||
displayRenderForm(postParsed.edit_post).then(function(html) | |||||
{ | |||||
resolve(html); | |||||
}).catch(function(error) | |||||
{ | |||||
reject(error); | |||||
}); | |||||
} | |||||
else if(postParsed.edit_post_2) | |||||
{ | |||||
sql.editPost(postParsed).then(function(html) | |||||
{ | |||||
resolve(html); | |||||
}).catch(function(error) | |||||
{ | |||||
reject(error); | |||||
}); | |||||
} | |||||
else | |||||
{ | |||||
resolve(""); | |||||
} | |||||
}); | |||||
}; | |||||
module.exports= | |||||
{ | |||||
/** | |||||
* Method which calls helper functions which processes post data for editing posts | |||||
* and calls a function which displays all the posts in a table | |||||
* | |||||
* @param postData | |||||
*/ | |||||
main: function(postData) | |||||
{ | |||||
return new Promise(function(resolve, reject) | |||||
{ | |||||
Promise.all([processPost(postData), | |||||
postsTable()]).then(function(html) | |||||
{ | |||||
resolve("<br>" + html.join('')); | |||||
}).catch(function(error) | |||||
{ | |||||
console.log("error in edit post.js"); | |||||
reject(error); | |||||
}) | |||||
}); | |||||
} | |||||
}; |
@ -1,54 +0,0 @@ | |||||
<div class="col-md-6"> | |||||
<div class="blogPost"> | |||||
<h1 class="text-center">Server Controls</h1> | |||||
<div class="text-center"> | |||||
<form action="/admin" method="post"> | |||||
<input type="submit" name="clearCache" value="Clear Cache" class="btn btn-lg btn-secondary" /> | |||||
<input type="hidden" name="clear_cache" value="true"> | |||||
</form> | |||||
<br> | |||||
<form action="/admin" method="post"> | |||||
<input type="submit" name="gitPull" value="Pull from Git" class="btn btn-lg btn-secondary" /> | |||||
<input type="hidden" name="git_pull" value="true"> | |||||
</form> | |||||
</div> | |||||
</div> | |||||
<br> | |||||
<div class="blogPost"> | |||||
<h1 class="text-center">New Post</h1> | |||||
<form action="/admin" method ="post" class="p-2"> | |||||
<!-- Post category --> | |||||
<div class="form-group"> | |||||
<input class="form-control" type="text" name="add_post_category" required> | |||||
<label class="w3-label w3-validate">Category</label> | |||||
</div> | |||||
<!-- Post name --> | |||||
<div class="form-group"> | |||||
<input class="form-control" type="text" name="add_post_name" required> | |||||
<label class="w3-label w3-validate">Name</label> | |||||
</div> | |||||
<!-- Post header picture --> | |||||
<div class="form-group"> | |||||
<input class="form-control" type="text" name="add_post_picture" value="n/a" required> | |||||
<label class="w3-label w3-validate">Picture</label> | |||||
</div> | |||||
<!-- Post date --> | |||||
<div class="form-group"> | |||||
<input class="w3-input" type="date" name="add_post_date" required> | |||||
<label class="w3-label w3-validate">Date</label> | |||||
</div> | |||||
<div class="text-center"> | |||||
<input type="submit" name="submit" value="Add" | |||||
class="btn btn-lg btn-secondary"/> | |||||
</div> | |||||
</form> | |||||
</div> | |||||
</div> |
@ -1,77 +0,0 @@ | |||||
const utils = require('../../utils/utils.js'); | |||||
const sql = require('../../utils/sql'); | |||||
const qs = require('querystring'); | |||||
const Promise = require('promise'); | |||||
/** | |||||
* | |||||
* @param postData | |||||
* @return {*|Promise} | |||||
*/ | |||||
const processPost = function(postData) | |||||
{ | |||||
return new Promise(function(resolve, reject) | |||||
{ | |||||
var post = qs.parse(postData); | |||||
if(post.add_post_name) | |||||
{ | |||||
var urls = post.add_post_name; | |||||
urls = urls.split(" ").join("-"); | |||||
urls =urls.toLowerCase(); | |||||
var q = "insert into posts (category_id, picture_url, published, name, url) values "; | |||||
q += "('" + post.add_post_category + "', '" + post.add_post_picture + | |||||
"', '" + post.add_post_date + "', '" + post.add_post_name + "', '" + urls + "')"; | |||||
sql.insert(q).then(function() | |||||
{ | |||||
var map = require('../../utils/generateSiteMap'); | |||||
map.main(); | |||||
resolve(""); | |||||
}).catch(function(error) | |||||
{ | |||||
reject(error); | |||||
}) | |||||
} | |||||
else if(post.clear_cache) | |||||
{ | |||||
require("../../sites/blog.js").clearCache(); | |||||
require("../../includes/includes.js").clearCache(); | |||||
} | |||||
else if(post.git_pull) | |||||
{ | |||||
const execSync = require('child_process').execSync; | |||||
code = execSync('git pull') | |||||
} | |||||
else | |||||
{ | |||||
resolve(""); | |||||
} | |||||
}); | |||||
}; | |||||
module.exports= | |||||
{ | |||||
/** | |||||
* | |||||
* @param postData | |||||
* @return {*} | |||||
*/ | |||||
main: function(postData) | |||||
{ | |||||
return new Promise(function(resolve, reject) | |||||
{ | |||||
Promise.all([utils.include("./admin/posts/newPost.html"), processPost(postData)]).then(function(html) | |||||
{ | |||||
resolve(html.join('')); | |||||
}).catch(function(error) | |||||
{ | |||||
reject(error); | |||||
}) | |||||
}); | |||||
} | |||||
}; |
@ -0,0 +1,49 @@ | |||||
/** DB query */ | |||||
const sql = require('../utils/sql'); | |||||
/** Object used to render blog post previews */ | |||||
const blogBodyRenderer = require('./renderBlogPost'); | |||||
module.exports= | |||||
{ | |||||
/** | |||||
* Calls blog and sidebar modules to render blog contents in order | |||||
* | |||||
* @param requestURL | |||||
* @param request | |||||
* @returns {Promise} | |||||
*/ | |||||
main: function(requestURL, request, templateContext) | |||||
{ | |||||
return new Promise(function(resolve, reject) | |||||
{ | |||||
var page = request.query.page; | |||||
const splitURL = requestURL.split("/"); | |||||
if(splitURL.length >= 3) | |||||
{ | |||||
sql.getPostsFromCategory(splitURL[2]).then(function(posts) | |||||
{ | |||||
Promise.all([blogBodyRenderer.renderBatchOfPosts(requestURL, posts, page, 5, templateContext), | |||||
require('./renderNextBar').main(requestURL, page, 5, posts.length, templateContext)]).then(function() | |||||
{ | |||||
resolve(); | |||||
}); | |||||
}).catch(function() | |||||
{ | |||||
delete templateContext["posts"]; | |||||
resolve(); | |||||
}); | |||||
} | |||||
else | |||||
{ | |||||
//page is not found but, posts list will be empty | |||||
// so 404 will display | |||||
resolve(); | |||||
} | |||||
}); | |||||
} | |||||
}; |
@ -0,0 +1,32 @@ | |||||
const sql = require('../utils/sql'); | |||||
const blogPostRenderer = require('./renderBlogPost.js'); | |||||
module.exports= | |||||
{ | |||||
/** | |||||
* Renders the previews of recent blog blog and the side bar | |||||
* | |||||
* @param res | |||||
* @param fileName request url | |||||
*/ | |||||
main: function(requestURL, request, templateContext) | |||||
{ | |||||
var page = request.query.page; | |||||
return new Promise(function(resolve, reject) | |||||
{ | |||||
sql.getAllPosts().then(function(posts) | |||||
{ | |||||
Promise.all([blogPostRenderer.renderBatchOfPosts(requestURL, posts, page, 5, templateContext), | |||||
require('./renderNextBar').main(requestURL, page, 5, posts.length, templateContext)]).then(function() | |||||
{ | |||||
resolve(); | |||||
}); | |||||
}).catch(function(error) | |||||
{ | |||||
reject(error); | |||||
}) | |||||
}); | |||||
} | |||||
}; |
@ -0,0 +1,47 @@ | |||||
/** DB queries */ | |||||
const sql = require('../utils/sql'); | |||||
/** Object used to render blog post previews */ | |||||
const blogBodyRenderer = require('./renderBlogPost'); | |||||
module.exports= | |||||
{ | |||||
/** | |||||
* Calls blog and sidebar modules to render blog contents in order | |||||
* | |||||
* @param requestURL | |||||
* @returns {Promise|*} | |||||
*/ | |||||
main: function(requestURL, request, templateContext) | |||||
{ | |||||
return new Promise(function(resolve, reject) | |||||
{ | |||||
const splitURL = requestURL.split("/"); | |||||
//user entered /category/name/ or /category/name | |||||
if(splitURL.length == 3 || splitURL.length == 4) | |||||
{ | |||||
sql.getPost(requestURL).then(function(posts) | |||||
{ | |||||
if(posts.length != 0) | |||||
{ | |||||
blogBodyRenderer.renderBatchOfPosts(requestURL, posts, 1, 1, templateContext).then(function() | |||||
{ | |||||
resolve(); | |||||
}); | |||||
} | |||||
else | |||||
{ | |||||
resolve(); | |||||
} | |||||
}) | |||||
} | |||||
else | |||||
{ | |||||
//404 will print | |||||
resolve(); | |||||
} | |||||
}); | |||||
} | |||||
}; |
@ -0,0 +1,52 @@ | |||||
/** | |||||
* Determines if the requested page is out of bounds | |||||
* | |||||
* @param page current page | |||||
* @param postsPerPage - number of blog rendered on each page | |||||
* @param totalPosts - total blog in this category/total | |||||
* @returns {boolean} if this is a valid page | |||||
*/ | |||||
const isValidPage = function(page, postsPerPage, totalPosts) | |||||
{ | |||||
return !(page === 0 || page -1 >= totalPosts/postsPerPage); | |||||
}; | |||||
module.exports= | |||||
{ | |||||
/** | |||||
* Renders two buttons on the bottom of the page to | |||||
* go to the left or right | |||||
* | |||||
* Used by the home page and categories pages | |||||
* @param baseURL -- base url of page being rendered | |||||
* @param currentPage -- current page being rendered | |||||
* @param postsPerPage -- number of blog on each page | |||||
* @param totalPosts -- total amount of blog in the category | |||||
* @returns {Promise} promise which renders the buttons | |||||
*/ | |||||
main: function(baseURL, currentPage, postsPerPage, totalPosts, templateContext) | |||||
{ | |||||
if(typeof currentPage == "undefined") | |||||
currentPage = 1; | |||||
currentPage = Number(currentPage); | |||||
if(!isValidPage(currentPage, postsPerPage, totalPosts)) | |||||
{ | |||||
reject("Invalid Page"); | |||||
} | |||||
var nextPage = currentPage + 1; | |||||
var previousPage = currentPage - 1; | |||||
if (isValidPage(previousPage, postsPerPage, totalPosts)) | |||||
{ | |||||
templateContext.newPostsURL = baseURL + "?page=" + previousPage; | |||||
} | |||||
if (isValidPage(nextPage, postsPerPage, totalPosts)) | |||||
{ | |||||
templateContext.oldPostsURL = baseURL + "?page=" + nextPage | |||||
} | |||||
} | |||||
}; |
@ -0,0 +1,60 @@ | |||||
# MYSQL Schema | |||||
![](docs/blogSql.svg) | |||||
```mysql | |||||
create database jrtechs_blog; | |||||
use jrtechs_blog; | |||||
create table users( | |||||
user_id mediumint unsigned not null AUTO_INCREMENT, | |||||
user_name varchar(60) not null, | |||||
password char(64) not null, | |||||
salt char(64) not null, | |||||
primary key(user_id) | |||||
); | |||||
create table categories( | |||||
category_id mediumint unsigned not null AUTO_INCREMENT, | |||||
name varchar(60) not null, | |||||
url varchar(60) not null, | |||||
primary key(category_id) | |||||
); | |||||
create table posts( | |||||
post_id mediumint unsigned not null AUTO_INCREMENT, | |||||
category_id mediumint unsigned not null, | |||||
picture_url varchar(100) not null, | |||||
published datetime not null, | |||||
name varchar(100) not null, | |||||
url varchar(100) not null, | |||||
primary key(post_id) | |||||
); | |||||
create table downloads( | |||||
download_id mediumint unsigned not null AUTO_INCREMENT, | |||||
file varchar(40) not null, | |||||
name varchar(40) not null, | |||||
download_count mediumint not null, | |||||
primary key(download_id) | |||||
); | |||||
create table popular_posts( | |||||
popular_post_id mediumint unsigned not null AUTO_INCREMENT, | |||||
post_id mediumint unsigned not null, | |||||
primary key(popular_post_id) | |||||
); | |||||
create table traffic_log( | |||||
log_id mediumint unsigned not null AUTO_INCREMENT, | |||||
url varchar(60) not null, | |||||
ip varchar(20) not null, | |||||
date datetime not null, | |||||
primary key(log_id) | |||||
); | |||||
grant all on jrtechs_blog.* to blog_user@localhost identified by "password"; | |||||
``` |
@ -1,59 +0,0 @@ | |||||
/** DB query */ | |||||
const sql = require('../utils/sql'); | |||||
/** Object used to render blog post previews */ | |||||
const batchPreview = require('../posts/renderBatchOfPreviewes'); | |||||
/** | |||||
* Renders all posts in a single category | |||||
* | |||||
* @param resultURL | |||||
* @returns {*} | |||||
*/ | |||||
const renderPosts = function(resultURL, page) | |||||
{ | |||||
const splitURL = resultURL.split("/"); | |||||
if(splitURL.length >= 3) | |||||
{ | |||||
return new Promise(function(resolve, reject) | |||||
{ | |||||
sql.getPostsFromCategory(splitURL[2]).then(function(posts) | |||||
{ | |||||
resolve(batchPreview.main(resultURL, posts, page, 5)); | |||||
}).catch(function(error) | |||||
{ | |||||
reject(error); | |||||
}) | |||||
}); | |||||
} | |||||
else | |||||
{ | |||||
reject("Page Not Found"); | |||||
} | |||||
}; | |||||
module.exports= | |||||
{ | |||||
/** | |||||
* Calls posts and sidebar modules to render blog contents in order | |||||
* | |||||
* @param requestURL | |||||
* @param request | |||||
* @returns {Promise} | |||||
*/ | |||||
main: function(requestURL, request) | |||||
{ | |||||
return new Promise(function(resolve, reject) | |||||
{ | |||||
var page = request.query.page; | |||||
Promise.all([renderPosts(requestURL, page), | |||||
require("../sidebar/sidebar.js").main()]).then(function(content) | |||||
{ | |||||
resolve(content.join('')); | |||||
}).catch(function(err) | |||||
{ | |||||
reject(err); | |||||
}) | |||||
}); | |||||
} | |||||
}; |
@ -1,46 +0,0 @@ | |||||
const sql = require('../utils/sql'); | |||||
const batchPreview = require('../posts/renderBatchOfPreviewes'); | |||||
/**Renders each recent post for the homepage of the website | |||||
* | |||||
* @param result | |||||
* @returns {*|Promise} | |||||
*/ | |||||
var renderRecentPosts = function(baseURL, page) | |||||
{ | |||||
return new Promise(function(resolve, reject) | |||||
{ | |||||
sql.getRecentPostSQL().then(function(posts) | |||||
{ | |||||
resolve(batchPreview.main(baseURL, posts, page, 5)); | |||||
}).catch(function(error) | |||||
{ | |||||
reject(error); | |||||
}) | |||||
}); | |||||
}; | |||||
module.exports= | |||||
{ | |||||
/** | |||||
* Renders the previews of recent blog posts and the side bar | |||||
* | |||||
* @param res | |||||
* @param fileName request url | |||||
*/ | |||||
main: function(requestURL, request) | |||||
{ | |||||
var page = request.query.page; | |||||
return new Promise(function(resolve, reject) | |||||
{ | |||||
Promise.all([renderRecentPosts(requestURL, page), require("../sidebar/sidebar.js").main()]).then(function(content) | |||||
{ | |||||
resolve(content.join('')); | |||||
}).catch(function(error) | |||||
{ | |||||
reject(error); | |||||
}); | |||||
}) | |||||
} | |||||
}; |
@ -1,68 +0,0 @@ | |||||
/** DB queries */ | |||||
const sql = require('../utils/sql'); | |||||
/** | |||||
* Function responsible for calling the appropriate sql requests to query | |||||
* database and serve correct blog post | |||||
* | |||||
* @param requestURL url requested from client | |||||
* @return {*|Promise} returns a resolved promise to preserve execution order | |||||
*/ | |||||
const renderPost = function(requestURL) | |||||
{ | |||||
return new Promise(function(resolve, reject) | |||||
{ | |||||
const splitURL = requestURL.split("/"); | |||||
//user entered /category/name/ or /category/name | |||||
if(splitURL.length == 3 || splitURL.length == 4) | |||||
{ | |||||
sql.getPost(requestURL).then(function(post) | |||||
{ | |||||
if(post != 0) | |||||
{ | |||||
return require("../posts/singlePost.js").renderPost(post); | |||||
} | |||||
else | |||||
{ | |||||
reject("Page Not Found"); | |||||
} | |||||
}).then(function(html) | |||||
{ | |||||
resolve("<div class='col-md-8'>" + html + "</div>"); | |||||
}).catch(function(error) | |||||
{ | |||||
reject(error); | |||||
}) | |||||
} | |||||
else | |||||
{ | |||||
reject("Page Not Found"); | |||||
} | |||||
}); | |||||
}; | |||||
module.exports= | |||||
{ | |||||
/** | |||||
* Calls posts and sidebar modules to render blog contents in order | |||||
* | |||||
* @param requestURL | |||||
* @returns {Promise|*} | |||||
*/ | |||||
main: function(requestURL, request) | |||||
{ | |||||
return new Promise(function(resolve, reject) | |||||
{ | |||||
Promise.all([renderPost(requestURL), | |||||
require("../sidebar/sidebar.js").main()]).then(function(content) | |||||
{ | |||||
resolve(content.join('')); | |||||
}).catch(function(error) | |||||
{ | |||||
reject(error); | |||||
}) | |||||
}); | |||||
} | |||||
}; |
@ -1,55 +0,0 @@ | |||||
module.exports= | |||||
{ | |||||
/** | |||||
* Renders a bunch of blog post previews to the user | |||||
* | |||||
* @param baseURL-- url of the page | |||||
* @param posts -- sql data about the posts to render | |||||
* @param currentPage -- the current page to render | |||||
* @param numOfPosts -- number of posts to render | |||||
* @returns {Promise} renders the html of the posts | |||||
*/ | |||||
main: function(baseURL, posts, currentPage, numOfPosts) | |||||
{ | |||||
if(typeof currentPage == "undefined") | |||||
{ | |||||
currentPage = 1; | |||||
} | |||||
else | |||||
{ | |||||
currentPage = Number(currentPage); | |||||
} | |||||
return new Promise(function(resolve, reject) | |||||
{ | |||||
const promises = []; | |||||
for(var i = (currentPage-1) * numOfPosts; i < (currentPage-1) * numOfPosts + numOfPosts; i++) | |||||
{ | |||||
if(i < posts.length) | |||||
{ | |||||
promises.push(new Promise(function(res, rej) | |||||
{ | |||||
require("../posts/singlePost.js") | |||||
.renderPreview(posts[i]).then(function(html) | |||||
{ | |||||
res(html); | |||||
}).catch(function(error) | |||||
{ | |||||
reject(error) | |||||
}) | |||||
})); | |||||
} | |||||
} | |||||
promises.push(require('../posts/renderNextBar').main(baseURL, currentPage, numOfPosts, posts.length)); | |||||
Promise.all(promises).then(function(content) | |||||
{ | |||||
resolve("<div class='col-md-8'>" + content.join('') + "</div>"); | |||||
}).catch(function(error) | |||||
{ | |||||
reject(error); | |||||
}); | |||||
}); | |||||
} | |||||
}; |
@ -1,66 +0,0 @@ | |||||
/** | |||||
* Determines if the requested page is out of bounds | |||||
* | |||||
* @param page current page | |||||
* @param postsPerPage - number of posts rendered on each page | |||||
* @param totalPosts - total posts in this category/total | |||||
* @returns {boolean} if this is a valid page | |||||
*/ | |||||
const isValidPage = function(page, postsPerPage, totalPosts) | |||||
{ | |||||
return !(page === 0 || page -1 >= totalPosts/postsPerPage); | |||||
}; | |||||
module.exports= | |||||
{ | |||||
/** | |||||
* Renders two buttons on the bottom of the page to | |||||
* go to the left or right | |||||
* | |||||
* Used by the home page and categories pages | |||||
* @param baseURL -- base url of page being rendered | |||||
* @param currentPage -- current page being rendered | |||||
* @param postsPerPage -- number of posts on each page | |||||
* @param totalPosts -- total amount of posts in the category | |||||
* @returns {Promise} promise which renders the buttons | |||||
*/ | |||||
main: function(baseURL, currentPage, postsPerPage, totalPosts) | |||||
{ | |||||
return new Promise(function(resolve, reject) | |||||
{ | |||||
if(!isValidPage(currentPage, postsPerPage, totalPosts)) | |||||
{ | |||||
reject("Invalid Page"); | |||||
} | |||||
var nextPage = currentPage + 1; | |||||
var previousPage = currentPage - 1; | |||||
var olderPosts = ""; | |||||
var newerPosts = ""; | |||||
if (isValidPage(previousPage, postsPerPage, totalPosts)) | |||||
{ | |||||
newerPosts = "<button class=\"btn btn-secondary btn-lg " + | |||||
"w3-padding-large w3-white w3-border\" onclick=\"location.href='" + | |||||
baseURL + "?page=" + previousPage + | |||||
"'\"><b>Newer Posts »</b></button>"; | |||||
} | |||||
if (isValidPage(nextPage, postsPerPage, totalPosts)) | |||||
{ | |||||
olderPosts = "<button class=\"btn btn-secondary btn-lg " + | |||||
"w3-padding-large w3-white w3-border\" onclick=\"location.href='" + | |||||
baseURL + "?page=" + nextPage + | |||||
"'\"><b>Older Posts »</b></button>"; | |||||
} | |||||
resolve(" <div class=\"row\">\n" + | |||||
" <div class=\"col-6\">" + newerPosts + "</div>\n" + | |||||
" <div class=\"col-6\"><span class=\"float-right\">" + olderPosts + "</span></div>\n" + | |||||
" <br><br></div>"); | |||||
}) | |||||
} | |||||
}; |
@ -1,28 +0,0 @@ | |||||
const postGenerator = require('../utils/renderBlogPost.js'); | |||||
module.exports= | |||||
{ | |||||
/** | |||||
* Renders a preview of the post with a link to view more | |||||
* | |||||
* @param res | |||||
* @param post | |||||
*/ | |||||
renderPreview: function(post) | |||||
{ | |||||
return postGenerator.generateBlogPost(post, 3); | |||||
}, | |||||
/** | |||||
* renderPost() displays a single blog post in it's entirety | |||||
* | |||||
* @param res result sent to user | |||||
* @param post sql data about the blog post | |||||
* @return {*|Promise} | |||||
*/ | |||||
renderPost: function(post) | |||||
{ | |||||
return postGenerator.generateBlogPost(post, -1); | |||||
} | |||||
}; |
@ -1,38 +0,0 @@ | |||||
const sql = require('../utils/sql'); | |||||
module.exports= | |||||
{ | |||||
/** | |||||
* Responsible for querying the database and displaying all | |||||
* categories that the blog has in the sidebar | |||||
* | |||||
* @param res | |||||
* @return {*|Promise} | |||||
*/ | |||||
main: function() | |||||
{ | |||||
return new Promise(function(resolve, reject) | |||||
{ | |||||
var content = "<br><br><div class=\"container\">"; | |||||
content += "<div class=\"list-group\">"; | |||||
content += " <a href=\"#\" class=\"list-group-item list-group-item-action flex-column align-items-start active\">\n" + | |||||
" <h5 class=\"mb-1\">Categories</h5>\n" + | |||||
" </a>"; | |||||
sql.getCategories().then(function(categories) | |||||
{ | |||||
categories.forEach(function(cat) | |||||
{ | |||||
content += "<a class=\"list-group-item\" href='/category/" + cat.url + "'>" + cat.name + "<br></a>"; | |||||
}); | |||||
content += "</div></div><br>"; | |||||
resolve(content); | |||||
}).catch(function(error) | |||||
{ | |||||
reject(error); | |||||
}); | |||||
}); | |||||
} | |||||
}; |
@ -1,35 +0,0 @@ | |||||
const sql = require('../utils/sql'); | |||||
module.exports= | |||||
{ | |||||
/**Renders the popular posts sidebar. | |||||
* | |||||
* @param res | |||||
* @returns {*|Promise} | |||||
*/ | |||||
main: function(res) | |||||
{ | |||||
return new Promise(function(resolve, reject) | |||||
{ | |||||
res.write("<div class=\"w3-card w3-margin\">"); | |||||
res.write("<div class=\"w3-container w3-padding\">" + | |||||
"<h4>Popular Posts</h4></div>"); | |||||
res.write("<div class=\"w3-sidebar w3-bar-block\">"); | |||||
sql.getPopularPosts().then(function(posts) | |||||
{ | |||||
posts.forEach(function(cat) | |||||
{ | |||||
console.log(cat); | |||||
res.write("<a class=\"w3-bar-item w3-button\" href='" | |||||
+ url + "'>" + p.name + "<br></a>"); | |||||
}); | |||||
res.write("</div></div>"); | |||||
resolve(); | |||||
}); | |||||
}); | |||||
} | |||||
}; |
@ -1,10 +0,0 @@ | |||||
<div class="container"> | |||||
<div class="list-group"> | |||||
<a href="#" class="list-group-item list-group-item-action flex-column align-items-start active"> | |||||
<h5 class="mb-1">Project Sites</h5> | |||||
</a> | |||||
<a class="list-group-item" href='https://jrtechs.net/steam/'>Steam Graph Analysis<br></a> | |||||
<a class="list-group-item" href='https://jrtechs.me/'>Portfolio<br></a> | |||||
<a class="list-group-item" href='https://clubpanda.jrtechs.net/'>Club Panda<br></a> | |||||
</div> | |||||
</div><br> |
@ -1,38 +0,0 @@ | |||||
const Promise = require('promise'); | |||||
const sql = require('../utils/sql'); | |||||
module.exports= | |||||
{ | |||||
/** Renders the the recent post sidebar. | |||||
* | |||||
* @returns {*|Promise} | |||||
*/ | |||||
main: function() | |||||
{ | |||||
return new Promise(function(resolve, reject) | |||||
{ | |||||
var content = "<div class=\"container\">"; | |||||
content +="<div class=\"list-group\">"; | |||||
content +=" <a href=\"#\" class=\"list-group-item list-group-item-action flex-column align-items-start active\">\n" + | |||||
" <h5 class=\"mb-1\">Recent Posts</h5>\n" + | |||||
" </a>"; | |||||
sql.getRecentPosts().then(function(posts) | |||||
{ | |||||
posts.forEach(function(p) | |||||
{ | |||||
var url = '/' + p.category + '/' + p.url; | |||||
content += "<a class=\"list-group-item\" href='" | |||||
+ url + "'>" + p.name + "<br></a>"; | |||||
}); | |||||
content +="</div></div>"; | |||||
resolve(content); | |||||
}).catch(function(error) | |||||
{ | |||||
reject(error); | |||||
}) | |||||
}); | |||||
} | |||||
}; |
@ -0,0 +1,66 @@ | |||||
<div class="row"> | |||||
<!-- Add Download --> | |||||
<div class="col-md-6"> | |||||
<div class="blogPost"> | |||||
<h1 class="text-center">Add Download</h1> | |||||
<form action="/admin/downloads/" method ="post" class="p-2"> | |||||
<div class="form-group"> | |||||
<input class="form-control" type="text" name="add_download_name" required> | |||||
<label>Download Name</label> | |||||
</div> | |||||
<div class="form-group"> | |||||
<input class="form-control" type="text" name="add_download_file" required> | |||||
<label>File name</label> | |||||
</div> | |||||
<div class="text-center"> | |||||
<input type="submit" name="add_download" value="Add Download" | |||||
class="btn btn-lg btn-secondary"/> | |||||
</div> | |||||
</form> | |||||
</div> | |||||
<br> | |||||
</div> | |||||
<!-- Downloads --> | |||||
<div class="col-md-6"> | |||||
<div class='blogPost'> | |||||
<h1 class="text-center">Downloads</h1> | |||||
<div class=""> | |||||
<table class="table table-striped"> | |||||
<thead class="thead-dark"> | |||||
<tr> | |||||
<td>Download Name</td> | |||||
<td>File</td> | |||||
<td>Download Count</td> | |||||
<td>Delete</td> | |||||
</tr> | |||||
</thead> | |||||
<tbody> | |||||
{for download in downloads} | |||||
<tr> | |||||
<td> | |||||
{download.name} | |||||
</td> | |||||
<td> | |||||
{download.file} | |||||
</td> | |||||
<td> | |||||
{download.download_count} | |||||
</td> | |||||
<td> | |||||
<form action="/admin/downloads/" method ="post" > | |||||
<input type="submit" name="submit" value="Delete" class="btn btn-secondary"/> | |||||
<input type='hidden' name='delete_download' value='{download.download_id}' /> | |||||
</form> | |||||
</td> | |||||
</tr> | |||||
{/for} | |||||
</tbody> | |||||
</table> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
</div> |
@ -0,0 +1,103 @@ | |||||
<div class="row"> | |||||
<div class="col-md-6"> | |||||
<div class="blogPost"> | |||||
<h1 class="text-center">Server Controls</h1> | |||||
<div class="text-center"> | |||||
<form action="/admin" method="post"> | |||||
<input type="submit" name="clearCache" value="Clear Cache" class="btn btn-lg btn-secondary" /> | |||||
<input type="hidden" name="clear_cache" value="true"> | |||||
</form> | |||||
<br> | |||||
<form action="/admin" method="post"> | |||||
<input type="submit" name="gitPull" value="Pull from Git" class="btn btn-lg btn-secondary" /> | |||||
<input type="hidden" name="git_pull" value="true"> | |||||
</form> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
<div class="col-md-6"> | |||||
<div class="blogPost"> | |||||
<h1 class="text-center">Add Category</h1> | |||||
<form action="/admin" method ="post" class="p-2"> | |||||
<div class="form-group"> | |||||
<input class="form-control" type="text" name="add_category" required> | |||||
<label>Category</label> | |||||
</div> | |||||
<div class="text-center"> | |||||
<input type="submit" name="submit" value="Add" | |||||
class="btn btn-lg btn-secondary"/> | |||||
</div> | |||||
</form> | |||||
</div> | |||||
<br> | |||||
</div> | |||||
</div> | |||||
<div class="row"> | |||||
<div class="col-md-6"> | |||||
<div class="blogPost"> | |||||
<h1 class="text-center">New Post</h1> | |||||
<form action="/admin" method ="post" class="p-2"> | |||||
<!-- Post category --> | |||||
<div class="form-group"> | |||||
<input class="form-control" type="text" name="add_post_category" required> | |||||
<label class="w3-label w3-validate">Category</label> | |||||
</div> | |||||
<!-- Post name --> | |||||
<div class="form-group"> | |||||
<input class="form-control" type="text" name="add_post_name" required> | |||||
<label class="w3-label w3-validate">Name</label> | |||||
</div> | |||||
<!-- Post header picture --> | |||||
<div class="form-group"> | |||||
<input class="form-control" type="text" name="add_post_picture" value="n/a" required> | |||||
<label class="w3-label w3-validate">Picture</label> | |||||
</div> | |||||
<!-- Post date --> | |||||
<div class="form-group"> | |||||
<input class="w3-input" type="date" name="add_post_date" required> | |||||
<label class="w3-label w3-validate">Date</label> | |||||
</div> | |||||
<div class="text-center"> | |||||
<input type="submit" name="submit" value="Add" | |||||
class="btn btn-lg btn-secondary"/> | |||||
</div> | |||||
</form> | |||||
</div> | |||||
</div> | |||||
<div class="col-md-6"> | |||||
<h1 class="text-center">Categories</h1> | |||||
<div class="blogPost"> | |||||
<table class="table table-striped"> | |||||
<thead class="thead-dark"> | |||||
<tr> | |||||
<td>Name</td> | |||||
<td>URL</td> | |||||
<td>Edit</td> | |||||
</tr> | |||||
</thead> | |||||
<tbody> | |||||
{for cat in categories} | |||||
<tr> | |||||
<td>{cat.name}</td> | |||||
<td>{cat.url}</td> | |||||
<td>{cat.category_id}</td> | |||||
</tr>> | |||||
{/for} | |||||
</tbody> | |||||
</table> | |||||
</div> | |||||
</div> | |||||
</div> |
@ -0,0 +1,65 @@ | |||||
{header} | |||||
<div class="container"> | |||||
{if loggedIn} | |||||
{>adminPage} | |||||
{else} | |||||
{if goodLoginAttempt} | |||||
<meta http-equiv="refresh" content="0"> | |||||
{/if} | |||||
<div class="row"> | |||||
{if banned} | |||||
<div class="align-content-center"> | |||||
<br> | |||||
<h1>Yikes</h1> | |||||
<br> | |||||
<img src="/includes/img/404.jpg" alt="Page not found meme" width="70%" /> | |||||
<br><br><br><br> | |||||
</div> | |||||
{else} | |||||
<div class="col-md-8"> | |||||
<div class="blogPost"> | |||||
<div class="text-center"> | |||||
<h2>Login</h2> | |||||
</div> | |||||
<form action="/admin/" method ="post" class="p-2"> | |||||
<div class="form-group"> | |||||
<label for="username1">User Name</label> | |||||
<input class="form-control" type="text" id="username1" name="username" placeholder="Enter username" required> | |||||
</div> | |||||
<div class="form-group"> | |||||
<label for="password1">Password</label> | |||||
<input class="form-control" type="password" name="password" id="password1" placeholder="Password" required> | |||||
</div> | |||||
<div class="text-center"> | |||||
<button class="btn btn-lg btn-secondary">Login</button> | |||||
</div> | |||||
<br> | |||||
</form> | |||||
{if invalid} | |||||
<p> | |||||
Invalid login attempt. | |||||
</p> | |||||
{/if} | |||||
<!-- | |||||
/\_/\ ___ | |||||
= o_o =_______ \ \ | |||||
__^ __( \.__) ) | |||||
(@)<_____>__(_____)____/ | |||||
--> | |||||
</div> | |||||
<br /><br /> | |||||
</div> | |||||
{/if} | |||||
</div> | |||||
{/if} | |||||
</div> | |||||
{footer} |
@ -0,0 +1,68 @@ | |||||
<div class="row"> | |||||
<div class="col-12"> | |||||
{if editPost} | |||||
<div class='blogPost'> | |||||
<h1 class="text-center">Edit Post</h1> | |||||
<form action="/admin/posts" method ="post" > | |||||
<div class="form-group"> | |||||
<input class="form-control" type="text" name="edit_cat_num" value='{post.category_id}' required> | |||||
<label class="w3-label w3-validate">Category Number</label> | |||||
</div> | |||||
<div class="form-group"> | |||||
<input class="form-control" type="text" name="edit_name_new" value='{post.name}' required> | |||||
<label class="w3-label w3-validate">Post Title</label> | |||||
</div> | |||||
<div class="form-group"> | |||||
<input class="form-control" type="text" name="edit_pic" value='{post.picture_url}' required> | |||||
<label class="w3-label w3-validate">Picture URL</label> | |||||
</div> | |||||
<div class="form-group"> | |||||
<input class="form-control" type="date" name="edit_date" value='{post.published}' required> | |||||
<label class="w3-label w3-validate">Published Date</label> | |||||
</div> | |||||
<div> | |||||
<input type="submit" name="submit" value="Edit" class="btn btn-lg btn-secondary"/> | |||||
</div> | |||||
<input type='hidden' name='edit_post_2' value='{post.post_id}'/> | |||||
</form> | |||||
</div> | |||||
<br> | |||||
{/if} | |||||
</div> | |||||
</div> | |||||
<div class="row"> | |||||
<div class="col-12"> | |||||
<div class='blogPost p-2'> | |||||
<h1 class="text-center">Posts</h1> | |||||
<table class="table table-striped"> | |||||
<thead class="thead-dark"> | |||||
<tr> | |||||
<td>Category #</td> | |||||
<td>Name</td> | |||||
<td>Header Picture</td> | |||||
<td>Date</td> | |||||
<td>Edit</td> | |||||
</tr> | |||||
</thead> | |||||
<tbody> | |||||
{for post in posts} | |||||
<tr> | |||||
<td>{post.category_id}</td> | |||||
<td>{post.name}</td> | |||||
<td>{post.picture_url}</td> | |||||
<td>{post.published}</td> | |||||
<td> | |||||
<form action="/admin/posts" method ="post" > | |||||
<input type="submit" name="submit" value="Edit" class="btn btn-secondary"/> | |||||
<input type='hidden' name='edit_post' value='{post.post_id}' /> | |||||
</form> | |||||
</td> | |||||
</tr> | |||||
{/for} | |||||
</tbody> | |||||
</table> | |||||
</div> | |||||
<br> | |||||
</div> | |||||
</div> |
@ -0,0 +1,62 @@ | |||||
{header} | |||||
<div class="container"> | |||||
<div class="row"> | |||||
<div class="col-md-8 col-12"> | |||||
{for post in posts} | |||||
<div class="blogPost"> | |||||
{if post.hasPicture} | |||||
<img src="/blogContent/headerImages/{post.picture_url}" style="width:100%;"> | |||||
{/if} | |||||
<div class="p-4"> | |||||
<h3><b>{post.name}</b></h3> | |||||
<h5> | |||||
<span class="w3-opacity">{post.published}</span> | |||||
</h5> | |||||
{post.blogBody} | |||||
</div> | |||||
</div> | |||||
<br> | |||||
<br> | |||||
{else} | |||||
<div class="row p-lg-0"> | |||||
<h1 class="align-content-center">Page Not Found</h1> | |||||
<div class="align-content-center"> | |||||
<img src="/includes/img/404.jpg" alt="Page not found" width="70%" /> | |||||
</div> | |||||
</div> | |||||
<br><br> | |||||
{/for} | |||||
<div class="row"> | |||||
<div class="col-6"> | |||||
{if newPostsURL} | |||||
<button class="btn btn-secondary btn-l" onclick="location.href='{newPostsURL}'"> | |||||
<b>Older Posts »</b> | |||||
</button> | |||||
{/if} | |||||
</div> | |||||
<div class="col-6"> | |||||
{if oldPostsURL} | |||||
<span class="float-right"> | |||||
<button class="btn btn-secondary btn-l" onclick="location.href='{oldPostsURL}'"> | |||||
<b>Older Posts »</b> | |||||
</button> | |||||
</span> | |||||
{/if} | |||||
</div> | |||||
</div> | |||||
<br> | |||||
</div> | |||||
<div class="col-md-4 col-4"> | |||||
{>sideBar} | |||||
</div> | |||||
</div> | |||||
</div> | |||||
{footer} |
@ -0,0 +1,36 @@ | |||||
<div class="container"> | |||||
<div class="list-group"> | |||||
<a href="#" class="list-group-item list-group-item-action flex-column align-items-start active"> | |||||
<h5 class="mb-1">Project Sites</h5> | |||||
</a> | |||||
<a class="list-group-item" href='https://jrtechs.net/steam/'>Steam Graph Analysis<br></a> | |||||
<a class="list-group-item" href='https://jrtechs.me/'>Portfolio<br></a> | |||||
<a class="list-group-item" href='https://clubpanda.jrtechs.net/'>Club Panda<br></a> | |||||
</div> | |||||
</div> | |||||
<br> | |||||
<div class="container"> | |||||
<div class="list-group"> | |||||
<a href="#" class="list-group-item list-group-item-action flex-column align-items-start active"> | |||||
<h5 class="mb-1">Recent Posts</h5> | |||||
</a> | |||||
{for recentPost in recentPosts} | |||||
<a class="list-group-item" href='{recentPost.url}'>{recentPost.name}<br></a> | |||||
{/for} | |||||
</div> | |||||
</div> | |||||
<br> | |||||
<div class="container"> | |||||
<div class="list-group"> | |||||
<a href="#" class="list-group-item list-group-item-action flex-column align-items-start active"> | |||||
<h5 class="mb-1">Categories</h5> | |||||
</a> | |||||
{for cat in categories} | |||||
<a class="list-group-item" href='{cat.url}'>{cat.name}<br></a> | |||||
{/for} | |||||
</div> | |||||
</div> | |||||
<br> | |||||