@ -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 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 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,37 +0,0 @@ | |||
//file io | |||
const utils = require('../../utils/utils.js'); | |||
//update db | |||
const sql = require('../../utils/sql'); | |||
//parse post data | |||
const qs = require('querystring'); | |||
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,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 posts and viewing a list of posts*/ | |||
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 posts 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 posts 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 posts page and handles post | |||
* data sent regarding editing posts. | |||
* | |||
* @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 posts.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,56 +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,30 +0,0 @@ | |||
const utils = require('../../utils/utils.js'); | |||
const sql = require('../../utils/sql'); | |||
const qs = require('querystring'); | |||
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,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"; | |||
``` |
@ -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> |