Personal blog written from scratch using Node.js, Bootstrap, and MySQL. https://jrtechs.net
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

367 lines
10 KiB

  1. const mysql = require('mysql');
  2. const sanitizer = require('sanitizer');
  3. const Promise = require('promise');
  4. const crypto = require('crypto');
  5. const qs = require('querystring');
  6. const utils = require('../utils/utils.js');
  7. var con = mysql.createConnection({
  8. host: "localhost",
  9. user: "blog_user",
  10. password: utils.getFileLine('../sql_secret'),
  11. database: "jrtechs_blog"
  12. });
  13. con.connect(function(err) {
  14. if (err) throw err;
  15. });
  16. /**
  17. * Function used to query the database for records
  18. *
  19. * @param sqlStatement
  20. * @returns {Array}
  21. */
  22. var fetch = function(sqlStatement)
  23. {
  24. return new Promise(function(resolve, reject)
  25. {
  26. con.query(sqlStatement, function (err, result)
  27. {
  28. if(err)
  29. {
  30. console.log(err);
  31. reject(err);
  32. }
  33. resolve(result);
  34. });
  35. });
  36. };
  37. module.exports=
  38. {
  39. /**
  40. * Function used to use insert statements into the database
  41. *
  42. * Don't worry, the input gets sanitized
  43. *
  44. * @param sqlStatement
  45. * @return the id of the new record - if there is one
  46. */
  47. insert : function(sqlStatement)
  48. {
  49. return new Promise(function(resolve, reject)
  50. {
  51. con.query(sanitizer.sanitize(sqlStatement), function (err, result)
  52. {
  53. if (err)
  54. {
  55. console.log(err);
  56. resolve(0);
  57. }
  58. resolve(result.insertId);
  59. });
  60. })
  61. },
  62. /**
  63. * function which fetches the sql info on a post based on it's sql id
  64. * @param id
  65. * @returns {Array}
  66. */
  67. getPostById: function(id)
  68. {
  69. console.log("select * from posts where post_id='" + id + "' limit 1");
  70. return new Promise(function(resolve, reject)
  71. {
  72. fetch("select * from posts where post_id='" + id + "' limit 1").then(function(post)
  73. {
  74. resolve(post[0]);
  75. }).catch(function(error)
  76. {
  77. reject(error);
  78. });
  79. });
  80. },
  81. /**
  82. * Not to be mistaken for getPostData() in @file utils/utils.js,
  83. * this function extracts a post entry from the sql server
  84. *
  85. * @param requestURL url user used to request blog post
  86. * @return {*} the entry found in the data base -- if any
  87. */
  88. getPost : function(requestURL)
  89. {
  90. return new Promise(function(resolve, reject)
  91. {
  92. var splitURL = requestURL.split("/")
  93. var q = "select * from categories where url='" + splitURL[1] + "'";
  94. fetch(q).then(function (result_category)
  95. {
  96. if(result_category.length != 0)
  97. {
  98. var q2 = "select * from posts where category_id='" +
  99. result_category[0].category_id +
  100. "' and url='" + splitURL[2] + "'";
  101. fetch(q2).then(function (result_posts)
  102. {
  103. if(result_posts != 0)
  104. {
  105. resolve(result_posts[0]);
  106. }
  107. else
  108. {
  109. resolve(0);
  110. }
  111. });
  112. }
  113. else
  114. {
  115. resolve(0);
  116. }
  117. });
  118. });
  119. },
  120. /**
  121. * Function used to retrieve all categories when making the sidebar
  122. *
  123. * @return {Promise<Response> | * | Array}
  124. */
  125. getCategories : function()
  126. {
  127. var q = "select * from categories";
  128. return fetch(q);
  129. },
  130. /**
  131. * Function which currently returns all posts of a particular
  132. * category from the database
  133. * @param requestURL
  134. * @return {*|Promise}
  135. */
  136. getPostsFromCategory: function(requestURL)
  137. {
  138. return new Promise(function(resolve, reject)
  139. {
  140. var q = "select * from categories where url ='" + requestURL + "'";
  141. fetch(q).then(function(categories)
  142. {
  143. if(categories.length != 0)
  144. {
  145. var qPosts = "select * from posts where category_id='" +
  146. categories[0].category_id + "' order by published desc";
  147. resolve(fetch(qPosts));
  148. }
  149. else
  150. {
  151. resolve([]);
  152. }
  153. });
  154. });
  155. },
  156. /**
  157. * Helper method which returns a list of objects which contains the url
  158. * and name of thee ten most recent posts
  159. *
  160. * {[name: , url: ],[name: , url: ],[name: , url: ],...}
  161. *
  162. * @return {*|Promise}
  163. */
  164. getRecentPosts: function()
  165. {
  166. return new Promise(function(resolve, reject)
  167. {
  168. var q = "select name,url, category_id from posts order " +
  169. "by post_id desc limit 10";
  170. fetch(q).then(function(sqlPosts)
  171. {
  172. var promises = [];
  173. sqlPosts.forEach(function(post)
  174. {
  175. promises.push(new Promise(function(res, rej)
  176. {
  177. var getCategory = "select url from categories where " +
  178. "category_id='" + post.category_id + "'";
  179. fetch(getCategory).then(function(urls)
  180. {
  181. var obj = new Object();
  182. obj.name = post.name;
  183. obj.url = post.url;
  184. obj.category = urls[0].url;
  185. res(obj);
  186. });
  187. }));
  188. });
  189. Promise.all(promises).then(function(goodies)
  190. {
  191. resolve(goodies);
  192. });
  193. });
  194. });
  195. },
  196. getPopularPosts: function()
  197. {
  198. return new Promise(function(resolve, reject)
  199. {
  200. var q = "select * from popular_posts";
  201. fetch(q).then(function(sqlPosts)
  202. {
  203. });
  204. });
  205. },
  206. /**
  207. * Function which checks to see if a user successfully logged in based on
  208. * the post data which they sent
  209. *
  210. * @param postData the post data
  211. * @return {*|Promise} a json object with {pass: , user: }
  212. * the pass is whether or not they logged in successfully and the user is
  213. * the username they successfully logged in with
  214. */
  215. checkLogin: function(postData)
  216. {
  217. var post = qs.parse(postData);
  218. return new Promise(function(resolve, reject)
  219. {
  220. var result = Object();
  221. result.pass = false;
  222. if(post.username && post.password)
  223. {
  224. var cleanName = sanitizer.sanitize(post.username);
  225. var cleanPassword = sanitizer.sanitize(post.password);
  226. var getSalt = "select * from users where user_name='" +
  227. cleanName + "'";
  228. fetch(getSalt).then(function(saltResult)
  229. {
  230. if(saltResult.length == 1)
  231. {
  232. var hashedPassword = crypto.createHash('sha256')
  233. .update(cleanPassword + saltResult[0].salt)
  234. .digest('hex');
  235. if(saltResult[0].password === hashedPassword)
  236. {
  237. result.pass = true;
  238. result.user = cleanName;
  239. resolve(result);
  240. }
  241. else
  242. {
  243. resolve(result)
  244. }
  245. }
  246. else
  247. {
  248. //incorrect username
  249. resolve(result);
  250. }
  251. })
  252. }
  253. else
  254. {
  255. //no login attempts were made
  256. resolve(result);
  257. }
  258. });
  259. },
  260. /**
  261. * Fetches a promise containing every post in the database
  262. * @returns {Array}
  263. */
  264. getAllPosts: function()
  265. {
  266. return fetch("select * from posts order by published desc");
  267. },
  268. /**
  269. * Fetches the sql category information based on it's id
  270. * @param categoryId
  271. * @returns {Array}
  272. */
  273. getCategory: function(categoryId)
  274. {
  275. return fetch("select * from categories where category_id='"
  276. + categoryId + "'");
  277. },
  278. getDownload: function(downloadURL)
  279. {
  280. var cleanD = sanitizer.sanitize(downloadURL);
  281. var q = "select * from downloads where url='" + cleanD + "' limit 1";
  282. return fetch(q);
  283. },
  284. editPost: function(postData)
  285. {
  286. var url = postData.edit_name_new.split(" ").join("-").toLowerCase();
  287. var q = "update posts ";
  288. q+= "set category_id='" + postData.edit_cat_num + "' ";
  289. q+= ",name='" + postData.edit_name_new + "' ";
  290. q+= ",url='" + url + "' ";
  291. q+= ",picture_url='" + postData.edit_pic + "' ";
  292. q+= ",published='" + postData.edit_date + "' ";
  293. q+= " where post_id='" + postData.edit_post_2 + "'";
  294. return module.exports.insert(q);
  295. },
  296. /**
  297. * Function which returns a promise which contains the string of the
  298. * entire sitemap for the blog.
  299. * @returns {Promise|*}
  300. */
  301. getSiteMap: function()
  302. {
  303. return new Promise(function(resolve, reject)
  304. {
  305. var base = "http://jrtechs.net/";
  306. var sm = base + "\n";
  307. var promises = [];
  308. module.exports.getCategories().then(function(categories)
  309. {
  310. categories.forEach(function(cat)
  311. {
  312. promises.push(new Promise(function(res, rej)
  313. {
  314. sm += base + "category/" + cat.url + "\n";
  315. module.exports.getPostsFromCategory(cat.url).then(function(posts)
  316. {
  317. posts.forEach(function(post)
  318. {
  319. sm += base + cat.url + "/" + post.url + "\n";
  320. });
  321. res()
  322. })
  323. }));
  324. });
  325. Promise.all(promises).then(function()
  326. {
  327. resolve(sm);
  328. }).catch(function(error)
  329. {
  330. throw error;
  331. });
  332. });
  333. });
  334. }
  335. };