5 Commits

24 changed files with 149 additions and 505 deletions
Split View
  1. +2
    -0
      .gitignore
  2. +5
    -5
      Dockerfile
  3. +0
    -2
      README.md
  4. +0
    -80
      admin/admin.js
  5. +0
    -71
      admin/analytics.js
  6. +1
    -1
      admin/posts.js
  7. +1
    -178
      blog/contact.js
  8. +1
    -2
      blog/renderBlogPost.js
  9. +3
    -13
      config.json
  10. +10
    -10
      docker-compose.yml
  11. +0
    -3
      includes/html/adminHeader.html
  12. +1
    -0
      package.json
  13. +0
    -10
      routes/admin/analytics.js
  14. +0
    -3
      routes/admin/index.js
  15. +1
    -0
      routes/index.js
  16. +1
    -2
      server.js
  17. +70
    -11
      sitemap.txt
  18. +7
    -3
      templates/admin/adminDownloads.html
  19. +0
    -20
      templates/admin/analytics.html
  20. +2
    -1
      templates/blog/contact.html
  21. +0
    -38
      utils/configLoader.js
  22. +11
    -3
      utils/pageBuilder.js
  23. +7
    -49
      utils/sql.js
  24. +26
    -0
      utils/utils.js

+ 2
- 0
.gitignore View File

@ -3,3 +3,5 @@
.vscode
node_modules
package-lock.json
sitemap.txt
blog.db

+ 5
- 5
Dockerfile View File

@ -5,17 +5,17 @@ FROM node:buster-slim
WORKDIR /src/
# installs node dependencies
ADD package.json package.json
RUN npm install
# installs pandoc for markdown to html
# need git so admin page can pull blog updates
RUN apt-get update && \
apt-get install sqlite3 -y && \
apt-get install pandoc -y && \
apt-get install git -y
# installs node dependencies
ADD package.json package.json
RUN npm install
# exposes port application runs on
EXPOSE 8000

+ 0
- 2
README.md View File

@ -102,8 +102,6 @@ unless otherwise stated.
- compression
- memory-cache --save
- request
- nodemailer
- nodemailer-smtp-transport
- whiskers
- node-pandoc
```

+ 0
- 80
admin/admin.js View File

@ -1,80 +0,0 @@
/**
* Determines what template and controls that will be
* displayed based on the url such as
* /
* /blog
* /downloads
*
* For each controls it calls that "pages" associated javascript file
* which fetches the template, deals with post data and gathers context
* for the template engine.
*/
//file IO
const utils = require('../utils/utils.js');
module.exports=
{
/**
*
* @param request -- used to get post data
* @param clientAddress -- used to see if user is banned for login
* @param templateContext -- used by whiskers for information to plug
* in the template
* @param filename -- specific admin page requested
* @returns {Promise} resolves once everything has been added to the template context
*/
main: function(request, clientAddress, templateContext, filename)
{
return new Promise(function(resolve, reject)
{
//if logged in
if(request.session && request.session.user)
{
templateContext.loggedIn = true;
utils.getPostData(request).then(function (postData)
{
var page = "./adminHome.js";
if(filename.includes('/downloads'))
{
page = "./adminDownloads.js";
}
else if(filename.includes("/posts"))
{
page = "./posts.js";
}
else if(filename.includes("/users"))
{
page = "./users.js";
}
else if(filename.includes("/analytics"))
{
page = "./analytics.js"
}
require(page).main(postData, templateContext).then(function(template)
{
templateContext.adminPage = template;
resolve();
}).catch(function(error)
{
console.log(error);
});
});
}
else
{
require("./login.js").main(request, clientAddress, templateContext)
.then(function()
{
resolve();
}).catch(function(err)
{
console.log(err);
reject(err);
})
}
});
}
};

+ 0
- 71
admin/analytics.js View File

@ -1,71 +0,0 @@
/** Whiskers template file */
const TEMPLATE_FILE = "admin/analytics.html";
const includes = require('../includes/includes.js');
//updates db
const sql = require('../utils/sql');
const generateData = function(templateContext)
{
return new Promise(function(resolve, reject)
{
var data = [];
sql.getTraffic().then(function(traffic)
{
var start = traffic[0].date;
var currentMonth = new Date(start.getUTCFullYear(), start.getMonth(), 1, 0,0,0);
templateContext.start = JSON.stringify(currentMonth);
var monthCount = 0;
for(var i = 0; i < traffic.length; i++)
{
var currentDate = traffic[i].date;
if(currentMonth.getMonth() != currentDate.getMonth())
{
var foo = new Object();
foo.x = currentMonth;
foo.y = monthCount;
data.push(foo);
monthCount = 0;
currentMonth = new Date(currentDate.getUTCFullYear(), currentDate.getMonth(), 1, 0,0,0);
}
monthCount = monthCount + 1;
}
templateContext.finish = JSON.stringify(currentMonth);
templateContext.dataset = JSON.stringify(data);
resolve();
});
});
};
module.exports=
{
/**
* Fetches context information for the admin blog page and handles post
* data sent regarding editing blog.
*
* @param templateContext json object used as the template context
* @returns {Promise} renders the template used for this page
*/
main: function(templateContext)
{
return new Promise(function(resolve, reject)
{
Promise.all([includes.fetchTemplate(TEMPLATE_FILE), generateData(templateContext)]).then(function(template)
{
templateContext.adminPage = template[0];
resolve();
}).catch(function(error)
{
console.log("error in add admin blog.js");
reject(error);
});
});
}
};

+ 1
- 1
admin/posts.js View File

@ -32,7 +32,7 @@ const processPostData = function(postData, renderContext)
renderContext.editPost = true;
sql.getPostById(postParsed.edit_post).then(function(post)
{
post.published = post.published.toISOString().split('T')[0];
post.published = new Date(post.published).toDateString();
renderContext.post = post;
resolve();
});

+ 1
- 178
blog/contact.js View File

@ -1,8 +1,5 @@
/**
* File which sends emails to me from
* a captcha protected form on the contact
* page.
*
* Handler for contact page
* @author Jeffery Russell 8-19-18
*/
@ -12,183 +9,10 @@ const utils = require('../utils/utils.js');
/** used for static files */
const includes = require('../includes/includes');
/** for parsing post data */
const qs = require('querystring');
/** cleans form submission */
const sanitizer = require('sanitizer');
/** used to send post data for the captcha */
const Request = require('request');
/** sends the email using a throw away gmail account */
const nodemailer = require("nodemailer");
/** agent for sending the email */
const smtpTransport = require('nodemailer-smtp-transport');
/** Used to load the config file from the disk */
const config = require('../utils/configLoader').getConfig();
//captcha secret
const CAPTCHA_SECRET = config.CAPTCHA_SECRET;
//password to gmail account
const EMAIL_PASSWORD = config.EMAIL_PASSWORD;
const TEMPLATE_FILE = "blog/contact.html";
const whiskers = require('whiskers');
/**
* Verifies if the captcha response recieved from the post data was
* valid, or are bots trying to get around the captcha
*
* @param data captcha data from post request
* @returns {Promise} resolves whether the captcha is valid
*/
const verifyCapcha = function(data)
{
const recaptcha_url = "https://www.google.com/recaptcha/api/siteverify?" +
"secret=" + CAPTCHA_SECRET + "&" +
"response=" + data;
return sync = new Promise(function(resolve, reject)
{
Request(recaptcha_url,
function (error, response, body)
{
if (!error && response.statusCode == 200)
{
const googleAnswer = JSON.parse(body);
if(googleAnswer.success == true)
{
resolve(true);
}
else
{
resolve(false);
}
}
else
{
resolve(false);
}
}
);
});
};
/**
* Sends a email to my personal emaail address using a throw away
* gmail account
*
* @param name from contact form
* @param email from contact form
* @param message from contact form
*/
const sendEmail = function(name, email, message)
{
const transporter = nodemailer.createTransport(smtpTransport({
service: 'gmail',
host: 'smtp.gmail.com',
auth: {
user: config.GMAIL_ACCOUNT,
pass: EMAIL_PASSWORD
}
}));
const email_message_html = "<h2><b>email:</b> " + email + "</h2><br>" +
"<h2><b>name:</b> " + name + "</h2><br>" +
"<h2>message:</h2><br><p>" + message + "</p>";
const email_message_text = "email: " + email + "\n" +
"name: " + name + "\n" +
"message: \n" + message;
const mailOptions =
{
to: config.DESTINATION_EMAIL, // list of receivers
subject: "Jrtechs.net form submission", // Subject line
text: email_message_text, // plaintext body
html: email_message_html
};
// send mail with defined transport object
transporter.sendMail(mailOptions, function(error, response)
{
if(error)
{
console.log(error);
}
else
{
console.log("Message sent: " + response);
}
transporter.close(); // shut down the connection pool, no more messages
});
};
/**
* If there was post data on the contact page, it processes it to see
* if it was a valid captcha request and sends an email. If no post data was sent,
* the normal form is displayed
*
* @param request -- main express request
* @returns {Promise} renders the html of the contact widget
*/
const processContactPage = function(request, templateContext)
{
return new Promise(function(resolve, reject)
{
utils.getPostData(request).then(function(postData)
{
const data = qs.parse(postData);
if(data.name &&
data.email &&
data["g-recaptcha-response"] &&
data.message)
{
verifyCapcha(sanitizer.sanitize(data["g-recaptcha-response"]))
.then(function(valid)
{
if(valid)
{
templateContext.messageSent = true;
resolve();
sendEmail(data.name, data.email, data.message);
}
else
{
resolve();
}
});
}
else
{
resolve();
}
}).catch(function(err)
{
reject(err);
})
});
};
module.exports =
{
/**
@ -206,7 +30,6 @@ module.exports =
var templateContext = Object();
Promise.all([includes.fetchTemplate(TEMPLATE_FILE),
processContactPage(request, templateContext),
includes.printHeader(templateContext),
includes.printFooter(templateContext),
require("./sidebar.js").main(templateContext)])

+ 1
- 2
blog/renderBlogPost.js View File

@ -47,8 +47,7 @@ module.exports=
{
if(post.picture_url !== "n/a")
post.hasPicture = true;
post.published = post.published.toDateString();
post.published = new Date(post.published).toDateString();
return;
},

+ 3
- 13
config.json View File

@ -1,16 +1,6 @@
{
"PORT": 8000,
"SESSION_SECRET": "random-data-to-seed-session-data",
"SQL_HOST": "localhost",
"SQL_DATABASE": "jrtechs_blog",
"SQL_USER": "root",
"SQL_PASSWORD": "password",
"CAPTCHA_SECRET": "captcha-secret",
"GMAIL_ACCOUNT": "email@gmail.com",
"EMAIL_PASSWORD": "email-password",
"DESTINATION_EMAIL": "destination email address"
"CACHE": false,
"ADMIN_CHECK": true,
"SESSION_SECRET": "random-data-to-seed-session-data"
}

+ 10
- 10
docker-compose.yml View File

@ -4,14 +4,14 @@ version: '3'
# mysql --port=3306 --host=127.0.0.1 -u root --password=password
services:
db:
image: mysql
command: --default-authentication-plugin=mysql_native_password
restart: always
environment:
MYSQL_ROOT_PASSWORD: password
volumes:
- "./db:/var/lib/mysql"
# db:
# image: mysql
# command: --default-authentication-plugin=mysql_native_password
# restart: always
# environment:
# MYSQL_ROOT_PASSWORD: password
# volumes:
# - "./db:/var/lib/mysql"
blog:
build: .
@ -20,5 +20,5 @@ services:
ports:
- 8000:8000
restart: always
links:
- db:database
# links:
# - db:database

+ 0
- 3
includes/html/adminHeader.html View File

@ -82,9 +82,6 @@
<li class="nav-item">
<a class="nav-link" href="/admin/users">Users</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/admin/analytics">Analytics</a>
</li>
</ul>
<ul class="nav navbar-nav navbar-right">
<li class="nav-item">

+ 1
- 0
package.json View File

@ -19,6 +19,7 @@
"rss": "^1.2.2",
"sanitizer": "^0.1.3",
"sendmail": "^1.4.1",
"sqlite3": "^5.0.2",
"whiskers": "^0.4.0"
},
"scripts": {

+ 0
- 10
routes/admin/analytics.js View File

@ -1,10 +0,0 @@
const routes = require('express').Router();
const builder = require('../../utils/pageBuilder');
routes.get('/', (request, result) =>
{
builder.constructAdminPage(request, result, require("../../admin/analytics").main)
});
module.exports = routes;

+ 0
- 3
routes/admin/index.js View File

@ -1,8 +1,5 @@
const routes = require('express').Router();
const analytics = require('./analytics');
routes.use('/analytics', analytics);
const login = require('./login');
routes.use('/login', login);

+ 1
- 0
routes/index.js View File

@ -60,6 +60,7 @@ routes.use('/rss', feed);
//blog home page
routes.get('/', (request, result) =>
{
console.log("ummmm ping?");
pageBuilder.buildBlogPage(request, result, require("../blog/homePage").main)
});

+ 1
- 2
server.js View File

@ -6,7 +6,7 @@
*/
/** Stores the configuration for the server */
const config = require('./utils/configLoader').getConfig();
const config = require('./utils/utils').getConfig();
/** Port for the server to run on */
const port = config.PORT;
@ -24,7 +24,6 @@ const compression = require('compression');
const map = require('./utils/generateSiteMap.js');
map.main();
/**session data for login */
const session = require('express-session');

+ 70
- 11
sitemap.txt View File

@ -1,24 +1,46 @@
http://jrtechs.net/
http://jrtechs.net/category/data-science
http://jrtechs.net/category/hardware
http://jrtechs.net/category/java
http://jrtechs.net/category/open-source
http://jrtechs.net/category/other
http://jrtechs.net/category/photography
http://jrtechs.net/category/programming
http://jrtechs.net/category/projects
http://jrtechs.net/category/web-development
http://jrtechs.net/hardware/2018-rochester-maker-faire
http://jrtechs.net/hardware/ddr4-ram-introduction
http://jrtechs.net/hardware/hard-drive-speeds
http://jrtechs.net/data-science/visualizing-fitbit-gps-data
http://jrtechs.net/data-science/quadtree-animations-with-matplotlib
http://jrtechs.net/data-science/implementing-a-quadtree-in-python
http://jrtechs.net/data-science/node2vec-with-steam-data
http://jrtechs.net/data-science/time-spent-in-steam-games
http://jrtechs.net/data-science/cuda-vs-cpu-performance
http://jrtechs.net/data-science/creating-pixel-art-with-open-cv
http://jrtechs.net/data-science/gans-in-pytorch
http://jrtechs.net/data-science/pytorch-headfirst
http://jrtechs.net/data-science/word-embeddings-part-2
http://jrtechs.net/data-science/word-embeddings
http://jrtechs.net/data-science/image-clustering-with-k-means
http://jrtechs.net/data-science/graphing-my-life-with-matplotlib
http://jrtechs.net/data-science/developing-an-ai-to-play-asteroids-part-1
http://jrtechs.net/data-science/csci-331-final-review
http://jrtechs.net/data-science/csci-331-review-2
http://jrtechs.net/data-science/csci-331-review-1
http://jrtechs.net/data-science/a-closer-look-at-fitbit-data
http://jrtechs.net/data-science/r-programming-language
http://jrtechs.net/data-science/is-using-ml-for-antivirus-safe
http://jrtechs.net/data-science/lets-build-a-genetic-algorithm
http://jrtechs.net/java/running-a-minecraft-server-with-docker
http://jrtechs.net/java/running-scala-code-in-docker
http://jrtechs.net/java/parallel-java-performance-overview
http://jrtechs.net/java/fun-with-functional-java
http://jrtechs.net/java/gremlin-in-10-minutes
http://jrtechs.net/java/top-three-recommended-java-ides
http://jrtechs.net/java/bash-usr-bin-java-cannot-execute-binary-file
http://jrtechs.net/other/college-cookbook
http://jrtechs.net/other/2018-in-review
http://jrtechs.net/other/morality-of-self-driving-cars
http://jrtechs.net/other/my-college-essay
http://jrtechs.net/other/deepfakes
http://jrtechs.net/other/why-do-i-blog
http://jrtechs.net/other/ways-to-avoid-getting-hacked
http://jrtechs.net/other/should-you-run-a-server-on-desktop-hardware
http://jrtechs.net/photography/segmenting-images-with-quadtrees
http://jrtechs.net/photography/the-rise-of-profile-photos
http://jrtechs.net/photography/photography-in-the-age-of-social-media
http://jrtechs.net/programming/csci-344-final-review
http://jrtechs.net/programming/multi-threaded-file-io
http://jrtechs.net/programming/sorting-algorithms
http://jrtechs.net/programming/knapsack-problem
http://jrtechs.net/programming/cs-theory-exam-2-review
@ -26,6 +48,8 @@ http://jrtechs.net/programming/everything-fibonacci
http://jrtechs.net/programming/c-to-c++-tutorial
http://jrtechs.net/programming/university-vs-teaching-yourself-programming
http://jrtechs.net/programming/using-english-conventions-to-write-clean-code
http://jrtechs.net/projects/diy-video-hosting-server
http://jrtechs.net/projects/github-graphs-project
http://jrtechs.net/projects/steam-friends-graph
http://jrtechs.net/projects/musical-floppy-drive-build-log
http://jrtechs.net/projects/musical-floppy-drives
@ -34,8 +58,43 @@ http://jrtechs.net/projects/ackermann-function-written-in-java
http://jrtechs.net/projects/batch-minecraft-launcher-with-auto-restart
http://jrtechs.net/projects/time-lapse-programming-zombie-game
http://jrtechs.net/projects/time-lapse-programming-pong
http://jrtechs.net/web-development/pandoc-syntax-highlighting-with-prism
http://jrtechs.net/web-development/node-rss-feed
http://jrtechs.net/web-development/lazy-loading-youtube-videos
http://jrtechs.net/web-development/node-website-optimization
http://jrtechs.net/web-development/node-vs-php
http://jrtechs.net/web-development/why-i-stopped-using-wordpress
http://jrtechs.net/web-development/history-of-jrtechs
http://jrtechs.net/hardware/creating-an-audio-switch
http://jrtechs.net/hardware/2018-rochester-maker-faire
http://jrtechs.net/hardware/ddr4-ram-introduction
http://jrtechs.net/hardware/hard-drive-speeds
http://jrtechs.net/other/2020-in-review
http://jrtechs.net/other/coming-out-as-bisexual
http://jrtechs.net/other/college-cookbook-part-3
http://jrtechs.net/other/flirting-with-burnout-at-rit
http://jrtechs.net/other/how-films-portray-control
http://jrtechs.net/other/working-remote
http://jrtechs.net/other/college-cookbook-part-2
http://jrtechs.net/other/2019-in-review
http://jrtechs.net/other/responsible-optimization
http://jrtechs.net/other/college-cookbook
http://jrtechs.net/other/2018-in-review
http://jrtechs.net/other/morality-of-self-driving-cars
http://jrtechs.net/other/my-college-essay
http://jrtechs.net/other/deepfakes
http://jrtechs.net/other/why-do-i-blog
http://jrtechs.net/other/ways-to-avoid-getting-hacked
http://jrtechs.net/other/should-you-run-a-server-on-desktop-hardware
http://jrtechs.net/open-source/creating-a-dynamic-github-profile
http://jrtechs.net/open-source/hosting-your-own-gitea-server
http://jrtechs.net/open-source/community-architecture
http://jrtechs.net/open-source/community-architecture-proposal
http://jrtechs.net/open-source/hfoss-quiz-1
http://jrtechs.net/open-source/ritlug-bugfix
http://jrtechs.net/open-source/shallow-dive-into-open-cv
http://jrtechs.net/open-source/foss-vs-floss
http://jrtechs.net/open-source/jupyter-will-change-your-life
http://jrtechs.net/open-source/towards-a-new-hacker-ethic
http://jrtechs.net/open-source/teaching-ssh-through-a-ctf
http://jrtechs.net/open-source/the-essential-vim-configuration

+ 7
- 3
templates/admin/adminDownloads.html View File

@ -1,7 +1,7 @@
<div class="row">
<!-- Add Download -->
<div class="col-md-6">
<div class="col-md-4">
<div class="blogPost">
<h1 class="text-center">Add Download</h1>
@ -24,15 +24,16 @@
</div>
<!-- Downloads -->
<div class="col-md-6">
<div class="col-md-8">
<div class='blogPost'>
<h1 class="text-center">Downloads</h1>
<div class="">
<table class="table table-striped">
<table class="table table-responsive table-striped">
<thead class="thead-dark">
<tr>
<td>Download Name</td>
<td>File</td>
<td>URL</td>
<td>Download Count</td>
<td>Delete</td>
</tr>
@ -44,6 +45,9 @@
<td>
{download.name}
</td>
<td class="w-25">
https://jrtechs.net/downloads/{download.name}
</td>
<td>
{download.file}
</td>

+ 0
- 20
templates/admin/analytics.html View File

@ -1,20 +0,0 @@
<h4 class="text-center">Traffic Graph</h4>
<div class="row">
<div class="col-12">
<div id="visualization"></div>
</div>
<br><br>
<script type="text/javascript">
var container = document.getElementById('visualization');
var items = {dataset};
var dataset = new vis.DataSet(items);
var options = {
start: {start},
end: {finish},
};
var graph2d = new vis.Graph2d(container, dataset, options);
</script>
</div>

+ 2
- 1
templates/blog/contact.html View File

@ -7,7 +7,7 @@
<h1>Message Sent</h1>
<p>I will try to get back to you within a week. Thank you for messaging me.</p>
{else}
<form action="/contact" method="post">
<form action="https://alert.jrtechs.net/contact" method="post">
<div class="card border-primary rounded-0">
<div class="card-header p-0">
<div class="bg-info text-white text-center py-2">
@ -48,6 +48,7 @@
</div>
<div class="form-group">
<input type="hidden" id="site" name="site" value="jrtechs.net">
<div class="g-recaptcha" data-sitekey="6LceWF8UAAAAAIsd7F6iY_Pywt4fJsJlFNPtEgi9"></div>
</div>

+ 0
- 38
utils/configLoader.js View File

@ -1,38 +0,0 @@
const utils = require('../utils/utils');
/**
* @author Jeffery Russell 11-24-18
*
* @type {{main: module.exports.main}}
*/
module.exports=
{
/**
* Verifies the contents of the config file
* and returns it. If the config is incomplete,
* it terminates the program.
*
* @returns {*|any}
*/
getConfig: function()
{
const configContents = ["PORT", "SESSION_SECRET",
"SQL_HOST", "SQL_DATABASE", "SQL_PASSWORD",
"CAPTCHA_SECRET", "GMAIL_ACCOUNT", "EMAIL_PASSWORD",
"DESTINATION_EMAIL"];
var config = utils.getFileAsJSON("./config.json");
for(var i = 0; i < configContents.length; i++)
{
if(!config.hasOwnProperty(configContents[i]))
{
console.log("Missing config property: " + configContents[i]);
process.exit(1);
}
}
return config;
}
}

+ 11
- 3
utils/pageBuilder.js View File

@ -6,6 +6,11 @@ const includes = require("../includes/includes");
const cache = require('memory-cache');
const CACHE_ENABLED = utils.getConfig()['CACHE'];
const ADMIN_CHECK = utils.getConfig()["ADMIN_CHECK"];
/** used to parse the request URL */
const url = require('url');
@ -128,7 +133,7 @@ module.exports =
loggedIn(request)
{
return(request.session && request.session.user);
return(ADMIN_CHECK == false || (request.session && request.session.user));
},
@ -139,7 +144,7 @@ module.exports =
page = 1;
page = Number(page);
const html = cache.get(filename + "?page=" + page);
const html = CACHE_ENABLED == true ? cache.get(filename + "?page=" + page) : null;
result.writeHead(200, {'Content-Type': 'text/html'});
if (html == null)
@ -156,7 +161,10 @@ module.exports =
const html = whiskers.render(content[0], templateContext);
result.write(html);
result.end();
cache.put(filename + "?page=" + page, html);
if(CACHE_ENABLED == true)
{
cache.put(filename + "?page=" + page, html);
}
}).catch(function (err)
{
cache.del(filename + "?page=" + page);

+ 7
- 49
utils/sql.js View File

@ -17,21 +17,10 @@ const crypto = require('crypto');
const qs = require('querystring');
/** Used to load the config file from the disk */
const config = require('../utils/configLoader').getConfig();
const config = require('../utils/utils').getConfig();
/** SQL connection */
const con = mysql.createConnection({
host: config.SQL_HOST,
port: config.SQL_PORT,
user: config.SQL_USER,
password: config.SQL_PASSWORD,
database: config.SQL_DATABASE
});
con.connect(function(err) {
if (err)
console.log(err);
});
const sqlite3 = require('sqlite3').verbose();
const con = new sqlite3.Database('./blog.db');
/**
@ -44,7 +33,8 @@ const fetch = function(sqlStatement)
{
return new Promise(function(resolve, reject)
{
con.query(sanitizer.sanitize(sqlStatement), function (err, result)
con.all(sanitizer.sanitize(sqlStatement), function (err, result)
{
if(err)
{
@ -69,14 +59,14 @@ const insert = function(sqlStatement)
{
return new Promise(function(resolve, reject)
{
con.query(sanitizer.sanitize(sqlStatement), function (err, result)
con.exec(sanitizer.sanitize(sqlStatement), function (err, result)
{
if (err)
{
console.log(err);
reject();
}
resolve(result.insertId);
resolve(0);
});
})
};
@ -551,37 +541,5 @@ module.exports=
});
});
},
/**
* Logs visited page for backend server analytics.
*
* @param ip
* @param page
*/
logTraffic: function(ip, page)
{
if(page.length > 40)
{
console.log("Error, request too long to log ip:"
+ ip + " page: " + page);
return;
}
if(ip.length > 20)
{
ip = "";
}
const q = "insert into traffic_log (url, ip, date) values " +
"('" + page + "', '" + ip + "', now())";
insert(q);
},
getTraffic: function()
{
return fetch("select * from traffic_log");
}
};

+ 26
- 0
utils/utils.js View File

@ -5,6 +5,7 @@
//used for file io
const fs = require('fs');
const path = require('path')
module.exports=
@ -101,4 +102,29 @@ module.exports=
}
});
},
/**
* Verifies the contents of the config file
* and returns it. If the config is incomplete,
* it terminates the program.
*
* @returns {*|any}
*/
getConfig: function()
{
const configContents = ["PORT", "SESSION_SECRET",
"CACHE", "ADMIN_CHECK"];
var config = JSON.parse(fs.readFileSync('/src/config.json', 'utf8'));
for(var i = 0; i < configContents.length; i++)
{
if(!config.hasOwnProperty(configContents[i]))
{
console.log("Missing config property: " + configContents[i]);
process.exit(1);
}
}
return config;
}
};

Loading…
Cancel
Save