2016-01-22 02:17:49 +00:00
|
|
|
var moment = require("moment");
|
|
|
|
var _ = require("lodash");
|
|
|
|
var fs = require('fs');
|
|
|
|
var mkdirp = require('mkdirp');
|
|
|
|
var jade = require('jade');
|
|
|
|
var markdown = require( "markdown" ).markdown;
|
|
|
|
var path = require('path');
|
|
|
|
var schemas = require('./schemas.js');
|
|
|
|
var config = require("./config.js").config;
|
|
|
|
|
|
|
|
var Post = function(data) {
|
|
|
|
this.data = this.sanitize(data);
|
|
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Prototype Setup
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
Post.prototype.data = {}
|
|
|
|
|
|
|
|
Post.prototype.get = function (name) {
|
|
|
|
return this.data[name];
|
|
|
|
}
|
|
|
|
|
|
|
|
Post.prototype.set = function (name, value) {
|
|
|
|
this.data[name] = value;
|
|
|
|
}
|
|
|
|
|
|
|
|
Post.prototype.sanitize = function (data) {
|
|
|
|
data = data || {};
|
|
|
|
schema = schemas.post;
|
|
|
|
return _.pick(_.defaults(data, schema), _.keys(schema));
|
|
|
|
}
|
|
|
|
|
2016-01-23 21:12:50 +00:00
|
|
|
Post.prototype.save = function (date, callback) {
|
2016-01-22 02:17:49 +00:00
|
|
|
var self = this;
|
2016-01-23 21:12:50 +00:00
|
|
|
if (date) {
|
|
|
|
this.set("updatedDate", date);
|
|
|
|
} else {
|
|
|
|
this.set("updatedDate", new Date());
|
|
|
|
}
|
2016-01-22 02:17:49 +00:00
|
|
|
this.data = this.sanitize(this.data);
|
|
|
|
db.collection("posts").update({uuid: this.get("uuid")}, this.data, {upsert: true}, function(err) {
|
|
|
|
callback(err);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Prototype Functions
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
// Parse a string of tags
|
|
|
|
// Returns a list of tags
|
|
|
|
Post.prototype.tagPost = function(str) {
|
|
|
|
this.set("tags", []);
|
|
|
|
|
|
|
|
// we don't need no stinking commas
|
|
|
|
var str = str.replace(/,/g,'');
|
|
|
|
|
|
|
|
// remove accents, swap ñ for n, etc
|
|
|
|
var from = "àáäâèéëêìíïîòóöôùúüûñç·/,:;&%";
|
|
|
|
var to = "aaaaeeeeiiiioooouuuunc-------";
|
|
|
|
for (var i=0, l=from.length ; i<l ; i++) {
|
|
|
|
str = str.replace(new RegExp(from.charAt(i), 'g'), to.charAt(i));
|
|
|
|
}
|
|
|
|
|
|
|
|
// Make into a sorted, unique array
|
|
|
|
var l = str.split(" ");
|
|
|
|
var list = []
|
|
|
|
for (i = 0; i < l.length; i ++) {
|
|
|
|
if (l[i]) {
|
|
|
|
list[i] = l[i].toLowerCase().trim()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
list = list.sort();
|
|
|
|
var unique = list.filter(function(elem, index, self) {
|
|
|
|
return index == self.indexOf(elem);
|
|
|
|
})
|
|
|
|
|
|
|
|
// Push these into the post.
|
|
|
|
for (var i = 0, size = unique.length; i < size; i++) {
|
|
|
|
if (unique[i]) {
|
|
|
|
this.data.tags.push({name: list[i]});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Function to get a YYYY-MM-DD format of the current postDate
|
|
|
|
// Arguments: None
|
|
|
|
// Returns: Date as String
|
|
|
|
Post.prototype.getShortDate = function () {
|
|
|
|
return moment(this.get("postDate")).format("YYYY-MM-DD");
|
|
|
|
}
|
|
|
|
|
|
|
|
// Function to return rendered markdown of a post
|
|
|
|
// Arguments: None
|
|
|
|
// Returns: Content as String
|
|
|
|
Post.prototype.renderMarkdown = function () {
|
|
|
|
return markdown.toHTML(this.get("markdown"));
|
|
|
|
}
|
|
|
|
|
|
|
|
// Function to get the relative url of a post, this sets the permalink structure
|
|
|
|
// Arguments: None
|
|
|
|
// Returns: URL as String
|
|
|
|
Post.prototype.getURL = function () {
|
|
|
|
var url = "/blog/";
|
|
|
|
url += moment(this.get("postDate")).format("YYYY/MM/");
|
|
|
|
url += this.get("slug") + '/';
|
|
|
|
return url;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Function to return the path of the post file
|
|
|
|
// Arguments: None
|
|
|
|
// Returns: Path as a string
|
|
|
|
Post.prototype.getFilePath = function () {
|
|
|
|
var file = path.join(this.getDirectory(),'index.html');
|
|
|
|
return file;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Function to return the post build directory
|
|
|
|
// Arguments: None
|
|
|
|
// Returns: Directory path as String
|
|
|
|
Post.prototype.getDirectory = function () {
|
|
|
|
var dir = path.join(config.genDir,this.getURL());
|
|
|
|
return dir;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Build a slug from a title string
|
|
|
|
// Arguments: None
|
|
|
|
// Returns: Post Slug as String
|
|
|
|
Post.prototype.makeSlug = function () {
|
|
|
|
str = this.get("title").replace(/^\s+|\s+$/g, ''); // trim
|
|
|
|
str = str.toLowerCase();
|
|
|
|
str = str.trim();
|
|
|
|
|
|
|
|
// remove accents, swap ñ for n, etc
|
|
|
|
var from = "àáäâèéëêìíïîòóöôùúüûñç·/_,:;&";
|
|
|
|
var to = "aaaaeeeeiiiioooouuuunc-------";
|
|
|
|
for (var i=0, l=from.length ; i<l ; i++) {
|
|
|
|
str = str.replace(new RegExp(from.charAt(i), 'g'), to.charAt(i));
|
|
|
|
}
|
|
|
|
|
|
|
|
str = str.replace(/[^a-z0-9 -]/g, '') // remove invalid chars
|
|
|
|
.replace(/\s+/g, '-') // collapse whitespace and replace by -
|
|
|
|
.replace(/-+/g, '-'); // collapse dashes
|
|
|
|
|
|
|
|
return str;
|
|
|
|
};
|
|
|
|
|
2016-01-23 22:57:19 +00:00
|
|
|
// Function to build static renderings of a particular post.
|
2016-01-22 02:17:49 +00:00
|
|
|
// Arguments: Callback function
|
|
|
|
// Returns: err
|
2016-01-23 22:57:19 +00:00
|
|
|
Post.prototype.buildPost = function (callback) {
|
2016-01-22 02:17:49 +00:00
|
|
|
var options = {
|
|
|
|
pretty: false,
|
|
|
|
post: this
|
|
|
|
};
|
|
|
|
|
|
|
|
console.log('Rendering post: '+this.get("title"));
|
|
|
|
var jadeOut = jade.renderFile('views/render-post.jade', options);
|
|
|
|
|
2016-01-23 21:12:50 +00:00
|
|
|
self = this;
|
|
|
|
|
|
|
|
mkdirp(self.getDirectory(), function (err) {
|
|
|
|
fs.writeFile(self.getFilePath(), jadeOut, 'utf-8', function (err) {
|
2016-01-23 22:57:19 +00:00
|
|
|
self.set('lastBuildDate', new Date());
|
|
|
|
self.save(self.get('lastBuildDate'), function (err) {
|
2016-01-23 21:12:50 +00:00
|
|
|
callback(err);
|
|
|
|
});
|
|
|
|
});
|
2016-01-22 02:17:49 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Independent Functions
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Function to find the most recent post generation.
|
|
|
|
// Returns a date object
|
2016-01-23 22:57:19 +00:00
|
|
|
Post.getLastBuildDate = function (callback) {
|
|
|
|
db.collection("posts").findOne({}, {lastBuildDate: 1}, {sort: {lastBuildDate: -1}},
|
2016-01-22 02:17:49 +00:00
|
|
|
function(err, doc) {
|
2016-01-23 22:57:19 +00:00
|
|
|
callback(err, doc.lastBuildDate);
|
2016-01-22 02:17:49 +00:00
|
|
|
}
|
|
|
|
)
|
|
|
|
};
|
|
|
|
|
|
|
|
// Function to find the most recent post upload date.
|
|
|
|
// Returns a date object
|
|
|
|
Post.getLastUploadDate = function (callback) {
|
|
|
|
db.collection("posts").findOne({}, {lastUploadDate: 1}, {sort: {lastUploadDate: -1}},
|
|
|
|
function (err, doc) {
|
|
|
|
callback(err, doc.lastUploadDate);
|
|
|
|
}
|
|
|
|
)
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// Get a specific post by it's UUID
|
|
|
|
// Returns post object
|
|
|
|
Post.getByUUID = function (uuid, callback) {
|
|
|
|
db.collection("posts").findOne({uuid: uuid}, function(err, doc) {
|
|
|
|
callback(err, new Post(doc));
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
// Function to get a count of current posts
|
|
|
|
// Returns count of posts
|
|
|
|
Post.countPosts = function(callback) {
|
|
|
|
db.collection("posts").find({}).count(function (err, count) {
|
|
|
|
if (err) console.log(err);
|
|
|
|
callback(err, count);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
// Function to get a list of posts of a certain count and starting at an offset
|
|
|
|
// Count and start are optional, when start is specified count must be specified.
|
|
|
|
// Returns a list of post objects
|
|
|
|
Post.getPosts = function(count, start, callback) {
|
|
|
|
if (typeof callback === undefined) {
|
|
|
|
if (typeof start === undefined) {
|
|
|
|
callback = count;
|
|
|
|
count = undefined;
|
|
|
|
start = undefined;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
callback = start;
|
|
|
|
start = undefined;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
var options = {}
|
|
|
|
if (start) options.skip=start;
|
|
|
|
if (count) options.limit=count;
|
|
|
|
options.sort = [['postDate', 'desc'],['title', 'asc']];
|
|
|
|
|
|
|
|
db.collection("posts").find({},options).toArray( function(err, docs) {
|
|
|
|
console.log(err);
|
|
|
|
posts = [];
|
|
|
|
for (i=0; i<docs.length; i++) {
|
|
|
|
posts.push(new Post(docs[i]));
|
|
|
|
}
|
|
|
|
callback(null, posts);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2016-01-23 22:57:19 +00:00
|
|
|
// Function to find posts that need to be built
|
2016-01-23 21:12:50 +00:00
|
|
|
// Inputs: Callback function
|
|
|
|
// Returns: list of Post objects
|
2016-01-23 23:19:37 +00:00
|
|
|
Post.getNeedsBuild = function (callback) {
|
2016-01-23 22:57:19 +00:00
|
|
|
db.collection("posts").find({
|
|
|
|
$where: "(this.lastBuildDate < this.updatedDate) && this.published"
|
|
|
|
}).toArray(
|
2016-01-23 21:12:50 +00:00
|
|
|
function (err, docs) {
|
|
|
|
if (err) console.log(err);
|
|
|
|
posts = [];
|
|
|
|
for (i=0; i<docs.length; i++) {
|
|
|
|
posts.push(new Post(docs[i]));
|
|
|
|
}
|
|
|
|
callback(null, posts);
|
|
|
|
}
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Function to find posts that need to be uploaded
|
|
|
|
// Inputs: Callback function
|
|
|
|
// Returns: List of Post objects
|
|
|
|
Post.getNeedsUpload = function (callback) {
|
|
|
|
db.collection("posts").find({
|
2016-01-23 22:47:15 +00:00
|
|
|
$where: '(this.lastUploadDate < this.updatedDate) && \
|
2016-01-23 22:57:19 +00:00
|
|
|
(this.lastBuildDate >= this.updatedDate) && \
|
2016-01-23 22:47:15 +00:00
|
|
|
this.published'
|
2016-01-23 21:12:50 +00:00
|
|
|
}).toArray( function (err, docs) {
|
|
|
|
if (err) console.log(err);
|
|
|
|
posts = [];
|
|
|
|
if (docs) {
|
|
|
|
for (i=0; i<docs.length; i++) {
|
|
|
|
posts.push(new Post(docs[i]));
|
|
|
|
}
|
|
|
|
callback(null, posts);
|
|
|
|
} else {
|
|
|
|
callback("No posts require upload.", null);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
);
|
|
|
|
}
|
2016-01-22 02:17:49 +00:00
|
|
|
|
|
|
|
// Export the Post object for external use.
|
|
|
|
module.exports = Post;
|