one final push, cleanup + organize + lint; made feeds/meta/plugins routes follow same pattern as other route files

v1.18.x
psychobunny 11 years ago
parent 1dbc47b890
commit c0cd6148f4

@ -16,9 +16,7 @@ var templates = require('./../../public/src/templates'),
var middleware = {}; var middleware = {};
/*
* Helper functions
*/
function routeThemeScreenshots(app, themes) { function routeThemeScreenshots(app, themes) {
var screenshotPath; var screenshotPath;
@ -170,6 +168,9 @@ function catch404(req, res, next) {
} }
} }
module.exports = function(app, data) { module.exports = function(app, data) {
middleware = require('./middleware')(app); middleware = require('./middleware')(app);

@ -22,7 +22,6 @@ var nconf = require('nconf'),
utils = require('./../../public/src/utils'), utils = require('./../../public/src/utils'),
templates = require('./../../public/src/templates'); templates = require('./../../public/src/templates');
var Admin = {};
function uploadImage(filename, req, res) { function uploadImage(filename, req, res) {
function done(err, image) { function done(err, image) {
@ -45,6 +44,89 @@ function uploadImage(filename, req, res) {
} }
} }
function uploadCategoryPicture(req, res, next) {
if (!req.user) {
return res.redirect('/403');
}
var allowedTypes = ['image/png', 'image/jpeg', 'image/jpg', 'image/gif'],
params = null, er;
try {
params = JSON.parse(req.body.params);
} catch (e) {
er = {
error: 'Error uploading file! Error :' + e.message
};
return res.send(req.xhr ? er : JSON.stringify(er));
}
if (allowedTypes.indexOf(req.files.userPhoto.type) === -1) {
er = {
error: 'Allowed image types are png, jpg and gif!'
};
res.send(req.xhr ? er : JSON.stringify(er));
return;
}
var filename = 'category-' + params.cid + path.extname(req.files.userPhoto.name);
uploadImage(filename, req, res);
}
function uploadFavicon(req, res, next) {
if (!req.user) {
return res.redirect('/403');
}
var allowedTypes = ['image/x-icon', 'image/vnd.microsoft.icon'],
er;
if (allowedTypes.indexOf(req.files.userPhoto.type) === -1) {
er = {error: 'You can only upload icon file type!'};
res.send(req.xhr ? er : JSON.stringify(er));
return;
}
file.saveFileToLocal('favicon.ico', req.files.userPhoto.path, function(err, image) {
fs.unlink(req.files.userPhoto.path);
if(err) {
er = {error: err.message};
return res.send(req.xhr ? er : JSON.stringify(er));
}
var rs = {path: image.url};
res.send(req.xhr ? rs : JSON.stringify(rs));
});
}
function uploadLogo(req, res, next) {
if (!req.user) {
return res.redirect('/403');
}
var allowedTypes = ['image/png', 'image/jpeg', 'image/pjpeg', 'image/jpg', 'image/gif'],
er;
if (allowedTypes.indexOf(req.files.userPhoto.type) === -1) {
er = {error: 'Allowed image types are png, jpg and gif!'};
res.send(req.xhr ? er : JSON.stringify(er));
return;
}
var filename = 'site-logo' + path.extname(req.files.userPhoto.name);
uploadImage(filename, req, res);
}
function getUsersCSV(req, res, next) {
user.getUsersCSV(function(err, data) {
res.attachment('users.csv');
res.setHeader('Content-Type', 'text/csv');
res.end(data);
});
}
module.exports = function(app, middleware, controllers) { module.exports = function(app, middleware, controllers) {
app.all('/api/admin/*', middleware.admin.isAdmin, middleware.prepareAPI); app.all('/api/admin/*', middleware.admin.isAdmin, middleware.prepareAPI);
app.all('/admin/*', middleware.admin.isAdmin); app.all('/admin/*', middleware.admin.isAdmin);
@ -104,129 +186,11 @@ module.exports = function(app, middleware, controllers) {
app.get('/api/admin/groups', controllers.admin.groups.get); app.get('/api/admin/groups', controllers.admin.groups.get);
app.namespace('/admin', function () { app.namespace('/admin', function () {
app.post('/category/uploadpicture', function(req, res) { app.get('/users/csv', getUsersCSV);
if (!req.user) {
return res.redirect('/403');
}
var allowedTypes = ['image/png', 'image/jpeg', 'image/jpg', 'image/gif'],
params = null, er;
try {
params = JSON.parse(req.body.params);
} catch (e) {
er = {
error: 'Error uploading file! Error :' + e.message
};
return res.send(req.xhr ? er : JSON.stringify(er));
}
if (allowedTypes.indexOf(req.files.userPhoto.type) === -1) {
er = {
error: 'Allowed image types are png, jpg and gif!'
};
res.send(req.xhr ? er : JSON.stringify(er));
return;
}
var filename = 'category-' + params.cid + path.extname(req.files.userPhoto.name);
uploadImage(filename, req, res);
});
app.post('/uploadfavicon', function(req, res) {
if (!req.user) {
return res.redirect('/403');
}
var allowedTypes = ['image/x-icon', 'image/vnd.microsoft.icon'],
er;
if (allowedTypes.indexOf(req.files.userPhoto.type) === -1) {
er = {error: 'You can only upload icon file type!'};
res.send(req.xhr ? er : JSON.stringify(er));
return;
}
file.saveFileToLocal('favicon.ico', req.files.userPhoto.path, function(err, image) {
fs.unlink(req.files.userPhoto.path);
if(err) {
er = {error: err.message};
return res.send(req.xhr ? er : JSON.stringify(er));
}
var rs = {path: image.url};
res.send(req.xhr ? rs : JSON.stringify(rs));
});
});
app.post('/uploadlogo', function(req, res) {
if (!req.user) {
return res.redirect('/403');
}
var allowedTypes = ['image/png', 'image/jpeg', 'image/pjpeg', 'image/jpg', 'image/gif'],
er;
if (allowedTypes.indexOf(req.files.userPhoto.type) === -1) {
er = {error: 'Allowed image types are png, jpg and gif!'};
res.send(req.xhr ? er : JSON.stringify(er));
return;
}
var filename = 'site-logo' + path.extname(req.files.userPhoto.name);
uploadImage(filename, req, res);
});
app.get('/users/csv', function(req, res) {
user.getUsersCSV(function(err, data) {
res.attachment('users.csv');
res.setHeader('Content-Type', 'text/csv');
res.end(data);
});
});
});
var custom_routes = { app.post('/category/uploadpicture', uploadCategoryPicture);
'routes': [], app.post('/uploadfavicon', uploadFavicon);
'api': [] app.post('/uploadlogo', uploadLogo);
};
plugins.ready(function() {
plugins.fireHook('filter:admin.create_routes', custom_routes, function(err, custom_routes) {
var route, routes = custom_routes.routes;
for (route in routes) {
if (routes.hasOwnProperty(route)) {
(function(route) {
app[routes[route].method || 'get']('/admin' + routes[route].route, function(req, res) {
routes[route].options(req, res, function(options) {
Admin.buildHeader(req, res, function (err, header) {
res.send(header + options.content + templates['admin/footer']);
});
});
});
}(route));
}
}
var apiRoutes = custom_routes.api;
for (route in apiRoutes) {
if (apiRoutes.hasOwnProperty(route)) {
(function(route) {
app[apiRoutes[route].method || 'get']('/api/admin' + apiRoutes[route].route, function(req, res) {
apiRoutes[route].callback(req, res, function(data) {
res.json(data);
});
});
}(route));
}
}
});
}); });
}; };

@ -13,152 +13,156 @@ var path = require('path'),
meta = require('./../meta'), meta = require('./../meta'),
plugins = require('./../plugins'), plugins = require('./../plugins'),
utils = require('./../../public/src/utils'), utils = require('./../../public/src/utils'),
pkg = require('./../../package.json'); pkg = require('./../../package.json'),
customTemplates = [];
module.exports = function(app, middleware, controllers) {
app.namespace('/api', function () {
app.all('*', middleware.updateLastOnlineTime, middleware.prepareAPI);
app.get('/user/uid/:uid', middleware.checkGlobalPrivacySettings, controllers.accounts.getUserByUID); function searchTerm(req, res, next) {
if (!plugins.hasListeners('filter:search.query')) {
return res.redirect('/404');
}
app.get('/get_templates_listing', function (req, res) { function searchPosts(callback) {
utils.walk(nconf.get('views_dir'), function (err, data) { plugins.fireHook('filter:search.query', {
data = data.concat(app.get_custom_templates()) index: 'post',
.filter(function(value, index, self) { query: req.params.term
return self.indexOf(value) === index; }, function(err, pids) {
}).map(function(el) { if (err) {
return el.replace(nconf.get('views_dir') + '/', ''); return callback(err);
}); }
res.json(data); posts.getPostSummaryByPids(pids, false, callback);
});
}); });
}
app.get('/config', controllers.api.getConfig);
function searchTopics(callback) {
app.get('/search/:term', function (req, res, next) { plugins.fireHook('filter:search.query', {
if (!plugins.hasListeners('filter:search.query')) { index: 'topic',
return res.redirect('/404'); query: req.params.term
}, function(err, tids) {
if (err) {
return callback(err);
} }
function searchPosts(callback) { topics.getTopicsByTids(tids, 0, callback);
plugins.fireHook('filter:search.query', { });
index: 'post', }
query: req.params.term
}, function(err, pids) {
if (err) {
return callback(err);
}
posts.getPostSummaryByPids(pids, false, callback); if ((req.user && req.user.uid) || meta.config.allowGuestSearching === '1') {
}); async.parallel([searchPosts, searchTopics], function (err, results) {
if (err) {
return next(err);
} }
function searchTopics(callback) { if(!results) {
plugins.fireHook('filter:search.query', { results = [];
index: 'topic', results[0] = results[1] = [];
query: req.params.term
}, function(err, tids) {
if (err) {
return callback(err);
}
topics.getTopicsByTids(tids, 0, callback);
});
} }
if ((req.user && req.user.uid) || meta.config.allowGuestSearching === '1') { return res.json({
async.parallel([searchPosts, searchTopics], function (err, results) { show_no_topics: results[1].length ? 'hide' : '',
if (err) { show_no_posts: results[0].length ? 'hide' : '',
return next(err); show_results: '',
} search_query: req.params.term,
posts: results[0],
if(!results) { topics: results[1],
results = []; post_matches : results[0].length,
results[0] = results[1] = []; topic_matches : results[1].length
} });
return res.json({
show_no_topics: results[1].length ? 'hide' : '',
show_no_posts: results[0].length ? 'hide' : '',
show_results: '',
search_query: req.params.term,
posts: results[0],
topics: results[1],
post_matches : results[0].length,
topic_matches : results[1].length
});
});
} else {
res.send(403);
}
}); });
} else {
res.send(403);
}
}
function upload(req, res, filesIterator, next) {
if(!req.user) {
return res.json(403, {message:'not allowed'});
}
var files = req.files.files;
if(!Array.isArray(files)) {
return res.json(500, {message: 'invalid files'});
}
if(Array.isArray(files[0])) {
files = files[0];
}
function deleteTempFiles() {
for(var i=0; i<files.length; ++i) {
fs.unlink(files[i].path);
}
}
function upload(req, res, filesIterator, next) { async.map(files, filesIterator, function(err, images) {
if(!req.user) { deleteTempFiles();
return res.json(403, {message:'not allowed'});
}
var files = req.files.files;
if(!Array.isArray(files)) {
return res.json(500, {message: 'invalid files'});
}
// multiple files if(err) {
if(Array.isArray(files[0])) { return res.send(500, err.message);
files = files[0]; }
}
function deleteTempFiles() { // IE8 - send it as text/html so browser won't trigger a file download for the json response
for(var i=0; i<files.length; ++i) { // malsup.com/jquery/form/#file-upload
fs.unlink(files[i].path); res.send(200, req.xhr ? images : JSON.stringify(images));
} });
} }
function uploadPost(req, res, next) {
upload(req, res, function(file, next) {
if(file.type.match(/image./)) {
posts.uploadPostImage(file, next);
} else {
posts.uploadPostFile(file, next);
}
}, next);
}
function uploadThumb(req, res, next) {
upload(req, res, function(file, next) {
if(file.type.match(/image./)) {
topics.uploadTopicThumb(file, next);
} else {
res.json(500, {message: 'Invalid File'});
}
}, next);
}
async.map(files, filesIterator, function(err, images) { function getModerators(req, res, next) {
deleteTempFiles(); categories.getModerators(req.params.cid, function(err, moderators) {
res.json({moderators: moderators});
});
}
function getTemplatesListing(req, res, next) {
utils.walk(nconf.get('views_dir'), function (err, data) {
data = data.concat(customTemplates)
.filter(function(value, index, self) {
return self.indexOf(value) === index;
}).map(function(el) {
return el.replace(nconf.get('views_dir') + '/', '');
});
if(err) { res.json(data);
return res.send(500, err.message); });
} }
// if this was not a XMLHttpRequest (hence the req.xhr check http://expressjs.com/api.html#req.xhr) module.exports = function(app, middleware, controllers) {
// then most likely it's submit via the iFrame workaround, via the jquery.form plugin's ajaxSubmit() app.namespace('/api', function () {
// we need to send it as text/html so IE8 won't trigger a file download for the json response app.all('*', middleware.updateLastOnlineTime, middleware.prepareAPI);
// malsup.com/jquery/form/#file-upload
// Also, req.send is safe for both types, if the response was an object, res.send will automatically submit as application/json customTemplates = app.get_custom_templates();
// expressjs.com/api.html#res.send
res.send(200, req.xhr ? images : JSON.stringify(images));
});
}
app.post('/post/upload', function(req, res, next) { app.get('/config', controllers.api.getConfig);
upload(req, res, function(file, next) {
if(file.type.match(/image./)) {
posts.uploadPostImage(file, next);
} else {
posts.uploadPostFile(file, next);
}
}, next);
});
app.post('/topic/thumb/upload', function(req, res, next) { app.get('/user/uid/:uid', middleware.checkGlobalPrivacySettings, controllers.accounts.getUserByUID);
upload(req, res, function(file, next) { app.get('/get_templates_listing', getTemplatesListing);
if(file.type.match(/image./)) { app.get('/search/:term', searchTerm);
topics.uploadTopicThumb(file, next); app.get('/categories/:cid/moderators', getModerators);
} else {
res.json(500, {message: 'Invalid File'});
}
}, next);
});
app.get('/categories/:cid/moderators', function(req, res) { app.post('/post/upload', uploadPost);
categories.getModerators(req.params.cid, function(err, moderators) { app.post('/topic/thumb/upload', uploadThumb);
res.json({moderators: moderators});
});
});
}); });
// this should be in the API namespace // this should be in the API namespace

@ -1,17 +1,16 @@
"use strict";
var user = require('./../user'), var user = require('./../user'),
categories = require('./../categories'), categories = require('./../categories'),
topics = require('./../topics'), topics = require('./../topics'),
posts = require('./../posts'); posts = require('./../posts');
var DebugRoute = function(app) { module.exports = function(app, middleware, controllers) {
app.namespace('/debug', function() { app.namespace('/debug', function() {
app.get('/uid/:uid', function (req, res) { app.get('/uid/:uid', function (req, res) {
if (!req.params.uid) {
if (!req.params.uid)
return res.redirect('/404'); return res.redirect('/404');
}
user.getUserData(req.params.uid, function (err, data) { user.getUserData(req.params.uid, function (err, data) {
if (data) { if (data) {
@ -53,12 +52,5 @@ var DebugRoute = function(app) {
} }
}); });
}); });
app.get('/test', function(req, res) {
res.send(200);
});
}); });
}; };
module.exports = DebugRoute;

@ -1,201 +1,202 @@
(function (Feeds) { "use strict";
var posts = require('../posts'),
topics = require('../topics'),
categories = require('../categories'),
rss = require('rss'), var posts = require('../posts'),
nconf = require('nconf'), topics = require('../topics'),
categories = require('../categories'),
ThreadTools = require('../threadTools'), rss = require('rss'),
CategoryTools = require('../categoryTools'); nconf = require('nconf'),
Feeds.createRoutes = function(app){ ThreadTools = require('../threadTools'),
app.get('/topic/:topic_id.rss', hasTopicPrivileges, generateForTopic); CategoryTools = require('../categoryTools');
app.get('/category/:category_id.rss', hasCategoryPrivileges, generateForCategory);
app.get('/recent.rss', generateForRecent);
app.get('/popular.rss', generateForPopular);
};
function hasTopicPrivileges(req, res, next) {
var tid = req.params.topic_id;
var uid = req.user ? req.user.uid || 0 : 0;
function hasTopicPrivileges(req, res, next) { ThreadTools.privileges(tid, uid, function(err, privileges) {
var tid = req.params.topic_id; if(err) {
var uid = req.user ? req.user.uid || 0 : 0; return next(err);
}
ThreadTools.privileges(tid, uid, function(err, privileges) { if(!privileges.read) {
if(err) { return res.redirect('403');
return next(err); }
}
if(!privileges.read) { return next();
return res.redirect('403'); });
} }
return next(); function hasCategoryPrivileges(req, res, next) {
}); var cid = req.params.category_id;
} var uid = req.user ? req.user.uid || 0 : 0;
function hasCategoryPrivileges(req, res, next) { CategoryTools.privileges(cid, uid, function(err, privileges) {
var cid = req.params.category_id; if(err) {
var uid = req.user ? req.user.uid || 0 : 0; return next(err);
}
CategoryTools.privileges(cid, uid, function(err, privileges) { if(!privileges.read) {
if(err) { return res.redirect('403');
return next(err); }
}
if(!privileges.read) { return next();
return res.redirect('403'); });
} }
return next();
});
}
function generateForTopic(req, res, next) {
var tid = req.params.topic_id;
function generateForTopic(req, res, next) { topics.getTopicWithPosts(tid, 0, 0, 25, function (err, topicData) {
var tid = req.params.topic_id; if (err) {
return next(err);
}
topics.getTopicWithPosts(tid, 0, 0, 25, function (err, topicData) { var description = topicData.posts.length ? topicData.posts[0].content : '';
if (err) { var image_url = topicData.posts.length ? topicData.posts[0].picture : '';
return next(err); var author = topicData.posts.length ? topicData.posts[0].username : '';
}
var description = topicData.posts.length ? topicData.posts[0].content : ''; var feed = new rss({
var image_url = topicData.posts.length ? topicData.posts[0].picture : ''; title: topicData.title,
var author = topicData.posts.length ? topicData.posts[0].username : ''; description: description,
feed_url: nconf.get('url') + '/topic/' + tid + '.rss',
var feed = new rss({ site_url: nconf.get('url') + '/topic/' + topicData.slug,
title: topicData.title, image_url: image_url,
description: description, author: author,
feed_url: nconf.get('url') + '/topic/' + tid + '.rss', ttl: 60
site_url: nconf.get('url') + '/topic/' + topicData.slug, }),
image_url: image_url, dateStamp;
author: author,
ttl: 60
}),
dateStamp;
// Add pubDate if topic contains posts
if (topicData.posts.length > 0) {
feed.pubDate = new Date(parseInt(topicData.posts[0].timestamp, 10)).toUTCString();
}
topicData.posts.forEach(function(postData) { // Add pubDate if topic contains posts
if (parseInt(postData.deleted, 10) === 0) { if (topicData.posts.length > 0) {
dateStamp = new Date(parseInt(parseInt(postData.edited, 10) === 0 ? postData.timestamp : postData.edited, 10)).toUTCString(); feed.pubDate = new Date(parseInt(topicData.posts[0].timestamp, 10)).toUTCString();
}
feed.item({
title: 'Reply to ' + topicData.title + ' on ' + dateStamp,
description: postData.content,
url: nconf.get('url') + '/topic/' + topicData.slug + '#' + postData.pid,
author: postData.username,
date: dateStamp
});
}
});
var xml = feed.xml(); topicData.posts.forEach(function(postData) {
res.type('xml').set('Content-Length', Buffer.byteLength(xml)).send(xml); if (parseInt(postData.deleted, 10) === 0) {
}); dateStamp = new Date(parseInt(parseInt(postData.edited, 10) === 0 ? postData.timestamp : postData.edited, 10)).toUTCString();
};
function generateForCategory(req, res, next) {
var cid = req.params.category_id;
categories.getCategoryById(cid, 0, 25, 0, function (err, categoryData) {
if (err) {
return next(err);
}
var feed = new rss({
title: categoryData.name,
description: categoryData.description,
feed_url: nconf.get('url') + '/category/' + cid + '.rss',
site_url: nconf.get('url') + '/category/' + categoryData.cid,
ttl: 60
});
// Add pubDate if category has topics
if (categoryData.topics.length > 0) feed.pubDate = new Date(parseInt(categoryData.topics[0].lastposttime, 10)).toUTCString();
categoryData.topics.forEach(function(topicData) {
feed.item({ feed.item({
title: topicData.title, title: 'Reply to ' + topicData.title + ' on ' + dateStamp,
url: nconf.get('url') + '/topic/' + topicData.slug, description: postData.content,
author: topicData.username, url: nconf.get('url') + '/topic/' + topicData.slug + '#' + postData.pid,
date: new Date(parseInt(topicData.lastposttime, 10)).toUTCString() author: postData.username,
date: dateStamp
}); });
}); }
var xml = feed.xml();
res.type('xml').set('Content-Length', Buffer.byteLength(xml)).send(xml);
}); });
};
function generateForRecent(req, res, next) { var xml = feed.xml();
topics.getLatestTopics(0, 0, 19, 'month', function (err, recentData) { res.type('xml').set('Content-Length', Buffer.byteLength(xml)).send(xml);
if(err){ });
return next(err);
}
var feed = new rss({ }
title: 'Recently Active Topics',
description: 'A list of topics that have been active within the past 24 hours',
feed_url: nconf.get('url') + '/recent.rss',
site_url: nconf.get('url') + '/recent',
ttl: 60
});
// Add pubDate if recent topics list contains topics function generateForCategory(req, res, next) {
if (recentData.topics.length > 0) { var cid = req.params.category_id;
feed.pubDate = new Date(parseInt(recentData.topics[0].lastposttime, 10)).toUTCString();
}
recentData.topics.forEach(function(topicData) { categories.getCategoryById(cid, 0, 25, 0, function (err, categoryData) {
feed.item({ if (err) {
title: topicData.title, return next(err);
url: nconf.get('url') + '/topic/' + topicData.slug, }
author: topicData.username,
date: new Date(parseInt(topicData.lastposttime, 10)).toUTCString() var feed = new rss({
}); title: categoryData.name,
description: categoryData.description,
feed_url: nconf.get('url') + '/category/' + cid + '.rss',
site_url: nconf.get('url') + '/category/' + categoryData.cid,
ttl: 60
}); });
var xml = feed.xml(); // Add pubDate if category has topics
res.type('xml').set('Content-Length', Buffer.byteLength(xml)).send(xml); if (categoryData.topics.length > 0) {
feed.pubDate = new Date(parseInt(categoryData.topics[0].lastposttime, 10)).toUTCString();
}
categoryData.topics.forEach(function(topicData) {
feed.item({
title: topicData.title,
url: nconf.get('url') + '/topic/' + topicData.slug,
author: topicData.username,
date: new Date(parseInt(topicData.lastposttime, 10)).toUTCString()
});
}); });
};
function generateForPopular(req, res, next) {
topics.getTopicsFromSet(0, 'topics:posts', 0, 19, function (err, popularData) {
if(err){
return next(err);
}
var feed = new rss({ var xml = feed.xml();
title: 'Popular Topics', res.type('xml').set('Content-Length', Buffer.byteLength(xml)).send(xml);
description: 'A list of topics that are sorted by post count', });
feed_url: nconf.get('url') + '/popular.rss', }
site_url: nconf.get('url') + '/popular',
ttl: 60 function generateForRecent(req, res, next) {
}); topics.getLatestTopics(0, 0, 19, 'month', function (err, recentData) {
if(err){
return next(err);
}
var feed = new rss({
title: 'Recently Active Topics',
description: 'A list of topics that have been active within the past 24 hours',
feed_url: nconf.get('url') + '/recent.rss',
site_url: nconf.get('url') + '/recent',
ttl: 60
});
// Add pubDate if recent topics list contains topics // Add pubDate if recent topics list contains topics
if (popularData.topics.length > 0) { if (recentData.topics.length > 0) {
feed.pubDate = new Date(parseInt(popularData.topics[0].lastposttime, 10)).toUTCString(); feed.pubDate = new Date(parseInt(recentData.topics[0].lastposttime, 10)).toUTCString();
} }
recentData.topics.forEach(function(topicData) {
feed.item({
title: topicData.title,
url: nconf.get('url') + '/topic/' + topicData.slug,
author: topicData.username,
date: new Date(parseInt(topicData.lastposttime, 10)).toUTCString()
});
});
popularData.topics.forEach(function(topicData) { var xml = feed.xml();
feed.item({ res.type('xml').set('Content-Length', Buffer.byteLength(xml)).send(xml);
title: topicData.title, });
url: nconf.get('url') + '/topic/' + topicData.slug, }
author: topicData.username,
date: new Date(parseInt(topicData.lastposttime, 10)).toUTCString() function generateForPopular(req, res, next) {
}); topics.getTopicsFromSet(0, 'topics:posts', 0, 19, function (err, popularData) {
if(err){
return next(err);
}
var feed = new rss({
title: 'Popular Topics',
description: 'A list of topics that are sorted by post count',
feed_url: nconf.get('url') + '/popular.rss',
site_url: nconf.get('url') + '/popular',
ttl: 60
}); });
var xml = feed.xml(); // Add pubDate if recent topics list contains topics
res.type('xml').set('Content-Length', Buffer.byteLength(xml)).send(xml); if (popularData.topics.length > 0) {
feed.pubDate = new Date(parseInt(popularData.topics[0].lastposttime, 10)).toUTCString();
}
popularData.topics.forEach(function(topicData) {
feed.item({
title: topicData.title,
url: nconf.get('url') + '/topic/' + topicData.slug,
author: topicData.username,
date: new Date(parseInt(topicData.lastposttime, 10)).toUTCString()
});
}); });
};
}(exports)); var xml = feed.xml();
res.type('xml').set('Content-Length', Buffer.byteLength(xml)).send(xml);
});
}
module.exports = function(app, middleware, controllers){
app.get('/topic/:topic_id.rss', hasTopicPrivileges, generateForTopic);
app.get('/category/:category_id.rss', hasCategoryPrivileges, generateForCategory);
app.get('/recent.rss', generateForRecent);
app.get('/popular.rss', generateForPopular);
};

@ -5,20 +5,19 @@ var nconf = require('nconf'),
meta = require('./../meta'), meta = require('./../meta'),
plugins = require('./../plugins'), plugins = require('./../plugins'),
metaRoute = require('./meta'), metaRoutes = require('./meta'),
apiRoute = require('./api'), apiRoutes = require('./api'),
admin = require('./admin'), adminRoutes = require('./admin'),
feedsRoute = require('./feeds'); feedRoutes = require('./feeds'),
pluginRoutes = require('./plugins');
module.exports = function(app, middleware) { module.exports = function(app, middleware) {
app.namespace(nconf.get('relative_path'), function() { app.namespace(nconf.get('relative_path'), function() {
//temp adminRoutes(app, middleware, controllers);
metaRoute.createRoutes(app); metaRoutes(app, middleware, controllers);
feedsRoute.createRoutes(app); apiRoutes(app, middleware, controllers);
feedRoutes(app, middleware, controllers);
admin(app, middleware, controllers);
apiRoute(app, middleware, controllers);
/** /**
* Every view has an associated API route. * Every view has an associated API route.
@ -122,83 +121,10 @@ module.exports = function(app, middleware) {
app.get('/users/search', middleware.buildHeader, middleware.checkGlobalPrivacySettings, controllers.users.getUsersForSearch); app.get('/users/search', middleware.buildHeader, middleware.checkGlobalPrivacySettings, controllers.users.getUsersForSearch);
app.get('/api/users/search', middleware.checkGlobalPrivacySettings, controllers.users.getUsersForSearch); app.get('/api/users/search', middleware.checkGlobalPrivacySettings, controllers.users.getUsersForSearch);
/* Misc */ pluginRoutes(app, middleware, controllers);
app.get('/sitemap.xml', controllers.sitemap);
app.get('/robots.txt', controllers.robots);
// Other routes
require('./plugins')(app);
// Debug routes
if (process.env.NODE_ENV === 'development') { if (process.env.NODE_ENV === 'development') {
require('./debug')(app); require('./debug')(app, middleware, controllers);
} }
var custom_routes = {
'routes': [],
'api': [],
'templates': []
};
app.get_custom_templates = function() {
return custom_routes.templates.map(function(tpl) {
return tpl.template;
});
};
plugins.ready(function() {
/*
* TO BE DEPRECATED post 0.4x
*/
plugins.fireHook('filter:server.create_routes', custom_routes, function(err, custom_routes) {
var route,
routes = custom_routes.routes;
for (route in routes) {
if (routes.hasOwnProperty(route)) {
(function(route) {
app[routes[route].method || 'get'](routes[route].route, function(req, res) {
routes[route].options(req, res, function(options) {
app.build_header({
req: options.req || req,
res: options.res || res
}, function (err, header) {
//res.send(header + options.content + templates.footer);
});
});
});
}(route));
}
}
var apiRoutes = custom_routes.api;
for (route in apiRoutes) {
if (apiRoutes.hasOwnProperty(route)) {
(function(route) {
app[apiRoutes[route].method || 'get']('/api' + apiRoutes[route].route, function(req, res) {
apiRoutes[route].callback(req, res, function(data) {
res.json(data);
});
});
}(route));
}
}
var templateRoutes = custom_routes.templates;
for (route in templateRoutes) {
if (templateRoutes.hasOwnProperty(route)) {
(function(route) {
app.get('/templates/' + templateRoutes[route].template, function(req, res) {
res.send(templateRoutes[route].content);
});
}(route));
}
}
});
});
}); });
}; };

@ -1,67 +1,78 @@
"use strict";
var path = require('path'), var path = require('path'),
nconf = require('nconf'), nconf = require('nconf'),
less = require('less'), less = require('less'),
meta = require('../meta'), meta = require('../meta'),
db = require('../database'), db = require('../database'),
plugins = require('../plugins'); plugins = require('../plugins'),
(function (Meta) { minificationEnabled = false;
Meta.createRoutes = function(app) {
app.get('/stylesheet.css', function(req, res) {
if (meta.css.cache) { function sendMinifiedJS(req, res, next) {
res.type('text/css').send(200, meta.css.cache); function sendCached() {
return; return res.type('text/javascript').send(meta.js.cache);
} }
db.getObjectFields('config', ['theme:type', 'theme:id'], function(err, themeData) { if (meta.js.cache) {
var themeId = (themeData['theme:id'] || 'nodebb-theme-vanilla'), sendCached();
baseThemePath = path.join(nconf.get('themes_path'), (themeData['theme:type'] && themeData['theme:type'] === 'local' ? themeId : 'nodebb-theme-vanilla')), } else {
paths = [baseThemePath, path.join(__dirname, '../../node_modules')], if (minificationEnabled) {
source = '@import "./theme";', meta.js.minify(function() {
x, numLESS; sendCached();
});
} else {
// Compress only
meta.js.concatenate(function() {
sendCached();
});
}
}
}
// Add the imports for each LESS file function sendStylesheet(req, res, next) {
for(x=0,numLESS=plugins.lessFiles.length;x<numLESS;x++) { if (meta.css.cache) {
source += '\n@import "./' + plugins.lessFiles[x] + '";'; res.type('text/css').send(200, meta.css.cache);
} return;
}
var parser = new (less.Parser)({ db.getObjectFields('config', ['theme:type', 'theme:id'], function(err, themeData) {
paths: paths var themeId = (themeData['theme:id'] || 'nodebb-theme-vanilla'),
}); baseThemePath = path.join(nconf.get('themes_path'), (themeData['theme:type'] && themeData['theme:type'] === 'local' ? themeId : 'nodebb-theme-vanilla')),
paths = [baseThemePath, path.join(__dirname, '../../node_modules')],
source = '@import "./theme";',
x, numLESS;
parser.parse(source, function(err, tree) { // Add the imports for each LESS file
if (err) { for(x=0,numLESS=plugins.lessFiles.length;x<numLESS;x++) {
res.send(500, err.message); source += '\n@import "./' + plugins.lessFiles[x] + '";';
return; }
}
meta.css.cache = tree.toCSS({ var parser = new (less.Parser)({
compress: true paths: paths
});
res.type('text/css').send(200, meta.css.cache);
});
}); });
});
app.get('/nodebb.min.js', function(req, res) { parser.parse(source, function(err, tree) {
var sendCached = function() { if (err) {
return res.type('text/javascript').send(meta.js.cache); res.send(500, err.message);
} return;
if (meta.js.cache) {
sendCached();
} else {
if (app.enabled('minification')) {
meta.js.minify(function() {
sendCached();
});
} else {
// Compress only
meta.js.concatenate(function() {
sendCached();
});
}
} }
meta.css.cache = tree.toCSS({
compress: true
});
res.type('text/css').send(200, meta.css.cache);
}); });
}; });
})(exports); }
module.exports = function(app, middleware, controllers) {
minificationEnabled = app.enabled('minification');
app.get('/stylesheet.css', sendStylesheet);
app.get('/nodebb.min.js', sendMinifiedJS);
app.get('/sitemap.xml', controllers.sitemap);
app.get('/robots.txt', controllers.robots);
};

@ -6,73 +6,184 @@ var nconf = require('nconf'),
validator = require('validator'), validator = require('validator'),
_ = require('underscore'), _ = require('underscore'),
async = require('async'), async = require('async'),
plugins = require('../plugins'),
PluginRoutes = function(app) { plugins = require('../plugins');
/**
* GET/PUT /plugins/fireHook to be deprecated after 0.4.x function setupPluginRoutes(app) {
* var custom_routes = {
'routes': [],
'api': [],
'templates': []
};
app.get_custom_templates = function() {
return custom_routes.templates.map(function(tpl) {
return tpl.template;
});
};
plugins.ready(function() {
/*
* TO BE DEPRECATED post 0.4x and replaced with something that isn't as complicated as this...
*/ */
app.get('/plugins/fireHook', function(req, res) { plugins.fireHook('filter:server.create_routes', custom_routes, function(err, custom_routes) {
// GET = filter var route,
plugins.fireHook('filter:' + req.query.hook, req.query.args, function(err, returnData) { routes = custom_routes.routes;
if (typeof returnData === 'object') {
res.json(200, returnData); for (route in routes) {
} else { if (routes.hasOwnProperty(route)) {
res.send(200, validator.escape(returnData)); (function(route) {
app[routes[route].method || 'get'](routes[route].route, function(req, res) {
routes[route].options(req, res, function(options) {
app.build_header({
req: options.req || req,
res: options.res || res
}, function (err, header) {
//res.send(header + options.content + templates.footer);
});
});
});
}(route));
} }
}); }
var apiRoutes = custom_routes.api;
for (route in apiRoutes) {
if (apiRoutes.hasOwnProperty(route)) {
(function(route) {
app[apiRoutes[route].method || 'get']('/api' + apiRoutes[route].route, function(req, res) {
apiRoutes[route].callback(req, res, function(data) {
res.json(data);
});
});
}(route));
}
}
var templateRoutes = custom_routes.templates;
for (route in templateRoutes) {
if (templateRoutes.hasOwnProperty(route)) {
(function(route) {
app.get('/templates/' + templateRoutes[route].template, function(req, res) {
res.send(templateRoutes[route].content);
});
}(route));
}
}
}); });
});
}
app.put('/plugins/fireHook', function(req, res) { function setupPluginAdminRoutes(app) {
// PUT = action var custom_routes = {
var hook = 'action:' + req.body.hook; 'routes': [],
if (plugins.hasListeners(hook)) { 'api': []
// Hook executes };
plugins.fireHook(hook, req.body.args);
plugins.ready(function() {
/*
* TO BE DEPRECATED post 0.4x and replaced with something that isn't as complicated as this...
*/
plugins.fireHook('filter:admin.create_routes', custom_routes, function(err, custom_routes) {
var route, routes = custom_routes.routes;
for (route in routes) {
if (routes.hasOwnProperty(route)) {
(function(route) {
app[routes[route].method || 'get']('/admin' + routes[route].route, function(req, res) {
routes[route].options(req, res, function(options) {
Admin.buildHeader(req, res, function (err, header) {
//res.send(header + options.content + templates['admin/footer']);
});
});
});
}(route));
}
} }
res.send(200); var apiRoutes = custom_routes.api;
for (route in apiRoutes) {
if (apiRoutes.hasOwnProperty(route)) {
(function(route) {
app[apiRoutes[route].method || 'get']('/api/admin' + apiRoutes[route].route, function(req, res) {
apiRoutes[route].callback(req, res, function(data) {
res.json(data);
});
});
}(route));
}
}
}); });
});
}
// Static Assets module.exports = function(app, middleware, controllers) {
app.get('/plugins/:id/*', function(req, res) { /**
var relPath = req._parsedUrl.pathname.replace(nconf.get('relative_path') + '/plugins/', ''), * GET/PUT /plugins/fireHook to be deprecated after 0.4.x
matches = _.map(plugins.staticDirs, function(realPath, mappedPath) { *
if (relPath.match(mappedPath)) { */
return mappedPath; app.get('/plugins/fireHook', function(req, res) {
} else { // GET = filter
return null; plugins.fireHook('filter:' + req.query.hook, req.query.args, function(err, returnData) {
} if (typeof returnData === 'object') {
}).filter(function(a) { return a; }); res.json(200, returnData);
if (matches) {
async.map(matches, function(mappedPath, next) {
var filePath = path.join(plugins.staticDirs[mappedPath], decodeURIComponent(relPath.slice(mappedPath.length)));
fs.exists(filePath, function(exists) {
if (exists) {
next(null, filePath);
} else {
next();
}
});
}, function(err, matches) {
// Filter out the nulls
matches = matches.filter(function(a) {
return a;
});
if (matches.length) {
res.sendfile(matches[0]);
} else {
res.redirect('/404');
}
});
} else { } else {
res.redirect('/404'); res.send(200, validator.escape(returnData));
} }
}); });
}; });
app.put('/plugins/fireHook', function(req, res) {
// PUT = action
var hook = 'action:' + req.body.hook;
if (plugins.hasListeners(hook)) {
// Hook executes
plugins.fireHook(hook, req.body.args);
}
res.send(200);
});
// Static Assets
app.get('/plugins/:id/*', function(req, res) {
var relPath = req._parsedUrl.pathname.replace(nconf.get('relative_path') + '/plugins/', ''),
matches = _.map(plugins.staticDirs, function(realPath, mappedPath) {
if (relPath.match(mappedPath)) {
return mappedPath;
} else {
return null;
}
}).filter(function(a) { return a; });
if (matches) {
async.map(matches, function(mappedPath, next) {
var filePath = path.join(plugins.staticDirs[mappedPath], decodeURIComponent(relPath.slice(mappedPath.length)));
fs.exists(filePath, function(exists) {
if (exists) {
next(null, filePath);
} else {
next();
}
});
}, function(err, matches) {
// Filter out the nulls
matches = matches.filter(function(a) {
return a;
});
if (matches.length) {
res.sendfile(matches[0]);
} else {
res.redirect('/404');
}
});
} else {
res.redirect('/404');
}
});
module.exports = PluginRoutes; setupPluginRoutes(app);
setupPluginAdminRoutes(app);
};

@ -14,12 +14,7 @@ var path = require('path'),
plugins = require('./plugins'), plugins = require('./plugins'),
logger = require('./logger'), logger = require('./logger'),
middleware = require('./middleware'), middleware = require('./middleware'),
routes = require('./routes'), routes = require('./routes');
admin = require('./routes/admin'),
apiRoute = require('./routes/api'),
feedsRoute = require('./routes/feeds'),
metaRoute = require('./routes/meta');
if(nconf.get('ssl')) { if(nconf.get('ssl')) {
server = require('https').createServer({ server = require('https').createServer({

Loading…
Cancel
Save