Skip to content

Instantly share code, notes, and snippets.

@alonronin
Last active December 12, 2015 22:14
Show Gist options
  • Save alonronin/27915c8d3f6ae115f3ff to your computer and use it in GitHub Desktop.
Save alonronin/27915c8d3f6ae115f3ff to your computer and use it in GitHub Desktop.
Ronin CMS
'use strict';
var app = require('./app');
var models = require('./models');
var async = require('async');
var _ = require('lodash');
/*
middle-wares
*/
var config = models.config.middleware();
var crumbs = models.navigation.crumbs();
var menu = models.navigation.menu();
var languages = models.language.middlware();
/*
Search for a post with current url:
res.locals.post
res.locals.page
if not than a navigation item:
res.locals.page
*/
var getByUrl = function(req, res, next) {
var params = req.params[0];
models.navigation
.findOne()
.where('url', params)
.where('show', true)
.populate('language')
.lean()
.exec(function (err, page) {
if(err) return next(err);
if(page){
res.locals.page = page;
res.locals.language = req.session.language = page.language;
return next();
}
models.posts.findOne()
.where('url', params)
.where('show', true)
.populate('navigation')
.lean()
.exec(function (err, post) {
if (err) return next(err);
if (post && post.navigation) {
res.locals.page = post.navigation;
res.locals.page.post = _.omit(post, 'navigation');
}
return next();
});
});
};
var pageModels = function(req, res, next){
var arr = [],
page = res.locals.page;
arr.push(models.posts.latest());
if(page) {
switch(page.template){
case 'homepage':
arr.push(models.homepage.fetch());
break;
case 'posts':
arr.push(models.posts.byNavigationId());
break;
}
}
async.each(arr, function(item, cb){
item(req, res, cb);
}, function(err){
next(err);
});
};
// Rewriter
//require('./rewrite').forEach(function(rule){
// app.get(encodeURI(rule.route), function(req, res){
// res.redirect(rule.status, rule.redirect);
// })
//});
// CMS rule
app.get('*', [languages, config, getByUrl, crumbs, menu, pageModels], function (req, res, next) {
if (!res.locals.page)
return next();
res.render(res.locals.page.template || 'index');
});
// catch 404 and forward to error handler
app.use(function (req, res, next) {
res.locals.page || (res.locals.page = {});
var config = (res.locals.config && res.locals.config._404) || {};
_.assign(res.locals.page, {
title: config.title || 'Not Found',
content: config.content || 'The requested document was not found on this server.'
});
var err = new Error('Not Found');
err.status = 404;
next(err);
});
'use strict';
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var Types = Schema.Types;
var _ = require('lodash');
var schema = new Schema({
language: { type: String, ref: 'language', default: 'he', hide: true }
});
/*
Return site config and some other:
res.locals.config
res.locals.http_params
*/
schema.statics.middleware = function() {
var config = this;
return function(req, res, next) {
var language = res.locals.language;
var q = config.findOne().where('language', language._id).lean().exec();
q.then(function(config) {
res.locals.http_params = {
query: req.query,
headers: req.headers,
body: req.body,
url: req.url,
debug: req.app.get('env') == 'development'
};
_.assign(config.site, req.session.config);
res.locals.config = config;
next();
}).end(next);
};
};
schema.formage = {
list: ['language'],
list_populate: ['language'],
section: 'Configuration'
};
module.exports = schema;
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var Types = Schema.Types;
var _ = require('lodash');
var schema = new Schema({
_id: { type: String, unique: true },
name: { type: String, unique: true },
url: { type: String },
order: { type: Number, editable: false, default: 0 },
active: { type: Boolean, default: true }
});
schema.methods.toString = function(){
return this.name;
};
schema.statics.middlware = function(){
var language = this;
return function(req, res, next){
language.find({ active: true })
.sort({ order: 1 })
.lean()
.exec(function(err, items) {
if(items) {
res.locals.language = req.session.language || items[0];
res.locals.languages = { items: items };
}
next(err);
})
}
};
schema.formage = {
list: ['name','url','active'],
order_by: ['order'],
sortable: 'order',
section: 'Configuration'
};
module.exports = schema;
'use strict';
var _ = require('lodash');
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var Types = Schema.Types;
var async = require('async');
var views = require('../views/');
var schema = new Schema({
language: { type: String, ref: 'language', default: 'en' },
parent: { type: Types.ObjectId, ref: 'navigation', limit: 1000 },
title: { type: String, required: true, trim: true },
description: { type: String },
url: { type: String, trim: true, lowercase: true, unique: true },
template: { type: String, enum: views, default: 'index' },
order: { type: Number, editable: false, default: 0 },
menu: { type: Boolean, 'default': true },
show: { type: Boolean, 'default': true },
meta: [{
name: { type: String },
content: { type: Types.Text }
}]
});
schema.methods.toString = function(){
return this.title;
};
schema.statics.findRecursive = function(language, cb) {
this.find({ language: language, show: true, menu: true })
.select('order parent url title description')
.sort({ parent: -1, order: 1 })
.lean()
.exec(function(err, items) {
if (err) cb(err);
var o = {};
items.forEach(function(item) {
item.sub = {items: []};
o[item._id] = item;
});
for (var i in o) {
var item = o[i];
if (item.parent) {
o[item.parent] && o[item.parent].sub.items.push(item);
delete o[i];
}
}
cb(null, _.values(o));
});
};
/*
Find crumbs of current page,
assumed to be at `res.locals.page`
results at
`res.locals.crumbs`
*/
schema.statics.crumbs = function() {
var nav = this;
return function(req, res, next) {
function parent(id) {
var q = nav.findById(id).select('parent url title').lean().exec();
q.then(function(page, err) {
if (err) return next(err);
if (page) {
crumbs.push(page);
return parent(page.parent);
}
res.locals.crumbs = crumbs.reverse();
next();
});
}
var crumbs = res.locals.crumbs = [];
if (res.locals.page && res.locals.page.post) {
crumbs.push(res.locals.page.post);
}
if (res.locals.page) {
crumbs.push(res.locals.page);
parent(res.locals.page.parent);
}
else next();
};
};
schema.statics.menu = function(){
var navigation = this;
return function(req, res, next) {
var crumbs = res.locals.crumbs;
var language = res.locals.language;
navigation.findRecursive(language._id, function(err, menu) {
menu.forEach(function(item, i){
item.dock = (crumbs&&crumbs[0]&&crumbs[0]._id.toString() === item._id.toString());
});
if(menu) res.locals.menu = {items: menu};
next(err);
});
};
};
schema.pre('validate', function(next) {
var url = this.url;
if (!url)
url = '/' + this.title;
url = url.replace(/[\?\'\"\@\!\#\$\%\^\&\*\(\)\+\=\_\~\{\}\[\]\\\|\,\;\:]/g, "")
.replace(/ +/g, "-")
.replace(/\-+/g, '-')
.replace(/(?:^\-|\-$)/g, '');
if (url.substr(0,1) !== '/')
url = '/' + url;
this.url = url.toLowerCase();
next();
});
schema.path('url').validate(function(v, callback){
var self = this;
async.each(['posts', 'navigation'], function(item, cb){
var query = self.db.model(item).findOne().where('url', self.url);
if('navigation' == item) query.ne('_id', self._id);
query.exec(function(err, url){
cb(err || url);
});
}, function(err){
callback(!err);
});
}, 'url already exists');
schema.formage = {
list: ['title', 'parent', 'language', 'url', 'template', 'menu', 'show'],
order_by: ['order'],
sortable: 'order',
list_populate: ['language', 'parent']
};
module.exports = schema;
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var Types = Schema.Types;
var async = require('async');
var _ = require('lodash');
var schema = new Schema({
navigation: { type: Types.ObjectId, ref: 'navigation' },
title: { type: String },
picture: {type: Types.Filepicker, widget: 'FilepickerPictureWidget'},
text: { type: Types.Html },
url: { type: String, trim: true, lowercase: true },
order: { type: Number, editable: false, default: 0 },
show: { type: Boolean, default: true }
});
schema.methods.toString = function(){
return this.title;
};
schema.pre('validate', function(next) {
var url = this.url;
if (!url)
url = '/' + this.title;
url = url.replace(/[\?\'\"\@\!\#\$\%\^\&\*\(\)\+\=\_\~\{\}\[\]\\\|\,\;\:]/g, "")
.replace(/ +/g, "-")
.replace(/\-+/g, '-')
.replace(/(?:^\-|\-$)/g, '');
if (url.substr(0,1) !== '/')
url = '/' + url;
this.url = url.toLowerCase();
next();
});
schema.path('url').validate(function(v, callback){
var self = this;
async.each(['posts', 'navigation'], function(item, cb){
var query = self.db.model(item).findOne().where('url', self.url);
if('posts' == item) query.ne('_id', self._id);
query.exec(function(err, url){
cb(err || url);
});
}, function(err){
callback(!err);
});
}, 'url already exists');
schema.statics.byNavigationId = function(){
var posts = this;
return function(req, res, cb){
var page = res.locals.page;
var config = res.locals.config;
posts
.find()
.where('navigation', page._id)
.where('show', 1)
.sort({'order': 1})
.lean()
.exec(function(err, results){
if(results.length) res.locals.page.posts = { items: results };
cb(err);
})
}
};
schema.formage = {
list: ['navigation', 'title', 'picture', 'url', 'show'],
list_populate: ['navigation'],
order_by: ['order'],
sortable: 'order'
};
module.exports = schema;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment