| @ -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 | |||||
|  | |||||
| ```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> | |||||