diff --git a/app.js b/app.js index e1201f1bd1..d9ac0296e5 100644 --- a/app.js +++ b/app.js @@ -27,8 +27,9 @@ async = require('async'), semver = require('semver'), winston = require('winston'), - pkg = require('./package.json'), path = require('path'), + pkg = require('./package.json'), + utils = require('./public/src/utils.js'), meta; // Runtime environment @@ -69,8 +70,8 @@ }); meta = require('./src/meta'); - nconf.set('url', nconf.get('base_url') + (nconf.get('use_port') ? ':' + nconf.get('port') : '') + nconf.get('relative_path') + '/'); - nconf.set('upload_url', nconf.get('url') + 'uploads/'); + nconf.set('url', nconf.get('base_url') + (nconf.get('use_port') ? ':' + nconf.get('port') : '') + nconf.get('relative_path') + path.sep); + nconf.set('upload_url', path.join(path.sep, nconf.get('relative_path'), 'uploads', path.sep)); nconf.set('base_dir', __dirname); winston.info('Initializing NodeBB v' + pkg.version + ', on port ' + nconf.get('port') + ', using Redis store at ' + nconf.get('redis:host') + ':' + nconf.get('redis:port') + '.'); @@ -108,16 +109,11 @@ var customTemplates = meta.config['theme:templates'] ? path.join(__dirname, 'node_modules', meta.config['theme:id'], meta.config['theme:templates']) : false; - // todo: replace below with read directory code, derp. - templates.init([ - 'header', 'footer', 'logout', 'outgoing', 'admin/header', 'admin/footer', 'admin/index', - 'emails/reset', 'emails/reset_plaintext', 'emails/email_confirm', 'emails/email_confirm_plaintext', - 'emails/header', 'emails/footer', - - 'noscript/header', 'noscript/home', 'noscript/category', 'noscript/topic' - ], customTemplates); - - + + utils.walk(path.join(__dirname, 'public/templates'), function (err, tplsToLoad) { + templates.init(tplsToLoad, customTemplates); + }); + plugins.ready(function() { templates.ready(webserver.init); }); diff --git a/public/src/forum/accountedit.js b/public/src/forum/accountedit.js index b681522457..858ef06bad 100644 --- a/public/src/forum/accountedit.js +++ b/public/src/forum/accountedit.js @@ -95,7 +95,7 @@ define(['forum/accountheader', 'uploader'], function(header, uploader) { $('#uploadPictureBtn').on('click', function() { $('#change-picture-modal').modal('hide'); - uploader.open(RELATIVE_PATH + '/user/uploadpicture', function(imageUrlOnServer) { + uploader.open(RELATIVE_PATH + '/user/uploadpicture', {}, function(imageUrlOnServer) { imageUrlOnServer = imageUrlOnServer + '?' + new Date().getTime(); $('#user-current-picture').attr('src', imageUrlOnServer); diff --git a/public/src/forum/admin/categories.js b/public/src/forum/admin/categories.js index 73eafde5df..47cf72b80a 100644 --- a/public/src/forum/admin/categories.js +++ b/public/src/forum/admin/categories.js @@ -183,8 +183,8 @@ define(['uploader'], function(uploader) { $('.upload-button').on('click', function() { var inputEl = this; - - uploader.open(RELATIVE_PATH + '/admin/category/uploadpicture', function(imageUrlOnServer) { + var cid = $(this).parents('li[data-cid]').attr('data-cid'); + uploader.open(RELATIVE_PATH + '/admin/category/uploadpicture', {cid:cid}, function(imageUrlOnServer) { inputEl.value = imageUrlOnServer; $(inputEl).parents('li[data-cid]').find('.preview-box').css('background', 'url(' + imageUrlOnServer + '?' + new Date().getTime() + ')'); modified(inputEl); @@ -270,7 +270,7 @@ define(['uploader'], function(uploader) { liEl = document.createElement('li'); var numResults = results.length, resultObj; - + for(var x=0;x' + '' + ' '+resultObj.name; - + groupsFrag.appendChild(liEl.cloneNode(true)); } - + groupsResultsEl.html(groupsFrag); }); - + groupsResultsEl.off().on('click', '[data-gpriv]', function(e) { var btnEl = $(this), gid = btnEl.parents('li[data-gid]').attr('data-gid'), diff --git a/public/src/forum/admin/settings.js b/public/src/forum/admin/settings.js index b384b3b378..acb74827f4 100644 --- a/public/src/forum/admin/settings.js +++ b/public/src/forum/admin/settings.js @@ -75,7 +75,7 @@ define(['uploader'], function(uploader) { }); $('#uploadLogoBtn').on('click', function() { - uploader.open(RELATIVE_PATH + '/admin/uploadlogo', function(image) { + uploader.open(RELATIVE_PATH + '/admin/uploadlogo', {}, function(image) { $('#logoUrl').val(image); }); @@ -83,7 +83,7 @@ define(['uploader'], function(uploader) { }); $('#uploadFaviconBtn').on('click', function() { - uploader.open(RELATIVE_PATH + '/admin/uploadfavicon', function(icon) { + uploader.open(RELATIVE_PATH + '/admin/uploadfavicon', {}, function(icon) { $('#faviconUrl').val(icon); }); diff --git a/public/src/forum/unread.js b/public/src/forum/unread.js index e0dd1dd7d7..5151eb37cb 100644 --- a/public/src/forum/unread.js +++ b/public/src/forum/unread.js @@ -71,6 +71,7 @@ define(function() { }); function onTopicsLoaded(topics) { + var html = templates.prepare(templates['unread'].blocks['topics']).parse({ topics: topics }); diff --git a/public/src/modules/uploader.js b/public/src/modules/uploader.js index 381e0d2cad..dd51395de2 100644 --- a/public/src/modules/uploader.js +++ b/public/src/modules/uploader.js @@ -2,12 +2,13 @@ define(function() { var module = {}; - module.open = function(route, callback) { + module.open = function(route, params, callback) { $('#upload-picture-modal').modal('show').removeClass('hide'); module.hideAlerts(); $('#uploadForm')[0].reset(); $('#uploadForm').attr('action', route); + $('#uploadForm').find('#params').val(JSON.stringify(params)); $('#pictureUploadSubmitBtn').off('click').on('click', function() { $('#uploadForm').submit(); diff --git a/public/src/templates.js b/public/src/templates.js index 5829ac5195..0c90900d9c 100644 --- a/public/src/templates.js +++ b/public/src/templates.js @@ -48,7 +48,7 @@ } }; - templates.prepare = function (raw_tpl, data) { + templates.prepare = function (raw_tpl) { var template = {}; template.html = raw_tpl; template.parse = parse; @@ -78,7 +78,9 @@ global.templates[file] = new template; loaded--; - if (loaded == 0) templates.ready(); + if (loaded === 0) { + templates.ready(); + } }); }(templatesToLoad[t])); } diff --git a/public/templates/admin/footer.tpl b/public/templates/admin/footer.tpl index c7fd7dde5c..48d6288c8e 100644 --- a/public/templates/admin/footer.tpl +++ b/public/templates/admin/footer.tpl @@ -17,6 +17,7 @@

You may only upload PNG, JPG, or GIF files under 256kb.

+
diff --git a/public/templates/footer.tpl b/public/templates/footer.tpl index 24e12add51..ed17d6d878 100644 --- a/public/templates/footer.tpl +++ b/public/templates/footer.tpl @@ -36,6 +36,7 @@

[[user:image_spec]]

+
diff --git a/src/routes/admin.js b/src/routes/admin.js index 88d3226039..e2aab456d6 100644 --- a/src/routes/admin.js +++ b/src/routes/admin.js @@ -104,46 +104,25 @@ var nconf = require('nconf'), return res.redirect('/403'); var allowedTypes = ['image/png', 'image/jpeg', 'image/jpg', 'image/gif']; - - if (allowedTypes.indexOf(req.files.userPhoto.type) === -1) { - res.send({ - error: 'Allowed image types are png, jpg and gif!' + var params = null; + try { + params = JSON.parse(req.body.params); + } catch (e) { + return res.send({ + error: 'Error uploading file! Error :' + e.message }); - return; } - var tempPath = req.files.userPhoto.path; - var extension = path.extname(req.files.userPhoto.name); - - if (!extension) { + if (allowedTypes.indexOf(req.files.userPhoto.type) === -1) { res.send({ - error: 'Error uploading file! Error : Invalid extension!' + error: 'Allowed image types are png, jpg and gif!' }); return; } - var filename = 'category' + utils.generateUUID() + extension; - var uploadPath = path.join(nconf.get('base_dir'), nconf.get('upload_path'), filename); - - winston.info('Attempting upload to: ' + uploadPath); - - var is = fs.createReadStream(tempPath); - var os = fs.createWriteStream(uploadPath); - - is.on('end', function () { - fs.unlinkSync(tempPath); - console.log(nconf.get('upload_url') + filename); - res.json({ - path: nconf.get('upload_url') + filename - }); - }); - - os.on('error', function (err) { - fs.unlinkSync(tempPath); - winston.err(err); - }); + var filename = 'category-' + params.cid + path.extname(req.files.userPhoto.name); - is.pipe(os); + uploadImage(filename, req, res); }); app.post('/uploadfavicon', function(req, res) { @@ -159,38 +138,7 @@ var nconf = require('nconf'), return; } - var tempPath = req.files.userPhoto.path; - var extension = path.extname(req.files.userPhoto.name); - - if (!extension) { - res.send({ - error: 'Error uploading file! Error : Invalid extension!' - }); - return; - } - - var filename = 'favicon.ico'; - var uploadPath = path.join(nconf.get('base_dir'), nconf.get('upload_path'), filename); - - winston.info('Attempting upload to: ' + uploadPath); - - var is = fs.createReadStream(tempPath); - var os = fs.createWriteStream(uploadPath); - - is.on('end', function () { - fs.unlinkSync(tempPath); - - res.json({ - path: nconf.get('upload_url') + filename - }); - }); - - os.on('error', function (err) { - fs.unlinkSync(tempPath); - winston.err(err); - }); - - is.pipe(os); + uploadImage('favicon.ico', req, res); }); app.post('/uploadlogo', function(req, res) { @@ -207,40 +155,45 @@ var nconf = require('nconf'), return; } - var tempPath = req.files.userPhoto.path; - var extension = path.extname(req.files.userPhoto.name); + var filename = 'site-logo' + path.extname(req.files.userPhoto.name); - if (!extension) { - res.send({ - error: 'Error uploading file! Error : Invalid extension!' - }); - return; - } + uploadImage(filename, req, res); + }); + }); - var filename = 'site-logo' + extension; - var uploadPath = path.join(nconf.get('base_dir'), nconf.get('upload_path'), filename); + function uploadImage(filename, req, res) { - winston.info('Attempting upload to: ' + uploadPath); + var tempPath = req.files.userPhoto.path; + var extension = path.extname(req.files.userPhoto.name); - var is = fs.createReadStream(tempPath); - var os = fs.createWriteStream(uploadPath); + if (!extension) { + res.send({ + error: 'Error uploading file! Error : Invalid extension!' + }); + return; + } - is.on('end', function () { - fs.unlinkSync(tempPath); + var uploadPath = path.join(nconf.get('base_dir'), nconf.get('upload_path'), filename); - res.json({ - path: nconf.get('upload_url') + filename - }); - }); + winston.info('Attempting upload to: ' + uploadPath); + var is = fs.createReadStream(tempPath); + var os = fs.createWriteStream(uploadPath); + + is.on('end', function () { + fs.unlinkSync(tempPath); - os.on('error', function (err) { - fs.unlinkSync(tempPath); - winston.err(err); + res.json({ + path: nconf.get('upload_url') + filename }); + }); - is.pipe(os); + os.on('error', function (err) { + fs.unlinkSync(tempPath); + winston.err(err); }); - }); + + is.pipe(os); + } var custom_routes = { diff --git a/src/routes/user.js b/src/routes/user.js index c97bcf6126..543bbb5162 100644 --- a/src/routes/user.js +++ b/src/routes/user.js @@ -161,12 +161,7 @@ var fs = require('fs'), is.on('end', function () { fs.unlinkSync(tempPath); - im.crop({ - srcPath: uploadPath, - dstPath: uploadPath, - width: 128, - height: 128 - }, function (err, stdout, stderr) { + function done(err) { if (err) { winston.err(err); res.send({ @@ -180,7 +175,7 @@ var fs = require('fs'), user.setUserField(uid, 'uploadedpicture', imageUrl); user.setUserField(uid, 'picture', imageUrl); - if (convertToPNG) { + if (convertToPNG && extension !== '.png') { im.convert([uploadPath, 'png:-'], function(err, stdout){ if (err) { @@ -195,11 +190,25 @@ var fs = require('fs'), }); } - res.json({ path: imageUrl }); - }); + } + + if(extension === '.gif') { + im.convert([uploadPath, '-coalesce', '-repage', '0x0', '-crop', '128x128+0+0', '+repage', 'uploadPath'], function(err, stdout) { + done(err); + }); + } else { + im.crop({ + srcPath: uploadPath, + dstPath: uploadPath, + width: 128, + height: 128 + }, function (err, stdout, stderr) { + done(err); + }); + } }); os.on('error', function (err) { diff --git a/src/topics.js b/src/topics.js index 86916f5ea9..a96effea17 100644 --- a/src/topics.js +++ b/src/topics.js @@ -456,9 +456,10 @@ var async = require('async'), } function sendUnreadTopics(topicIds) { + Topics.getTopicsByTids(topicIds, uid, function(topicData) { unreadTopics.topics = topicData; - unreadTopics.nextStart = start + topicIds.length; + unreadTopics.nextStart = stop + 1; if (!topicData || topicData.length === 0) { unreadTopics.no_topics_message = 'show'; } diff --git a/src/webserver.js b/src/webserver.js index 0ac8e00fe7..3606113cc8 100644 --- a/src/webserver.js +++ b/src/webserver.js @@ -807,7 +807,8 @@ var path = require('path'), var custom_routes = { 'routes': [], - 'api': [] + 'api': [], + 'templates': [] }; plugins.ready(function() { @@ -843,6 +844,17 @@ var path = require('path'), } } + var templateRoutes = custom_routes.templates; + for (var route in templateRoutes) { + if (templateRoutes.hasOwnProperty(route)) { + (function(route) { + app.get('/templates/' + templateRoutes[route].template, function(req, res) { + res.send(templateRoutes[route].content); + }); + }(route)); + } + } + }); }); diff --git a/src/websockets.js b/src/websockets.js index 8d16a66c08..310af2fbc9 100644 --- a/src/websockets.js +++ b/src/websockets.js @@ -106,12 +106,12 @@ websockets.init = function(io) { socket.on('disconnect', function() { - var index = userSockets[uid].indexOf(socket); + var index = (userSockets[uid] || []).indexOf(socket); if (index !== -1) { userSockets[uid].splice(index, 1); } - if (userSockets[uid].length === 0) { + if (userSockets[uid] && userSockets[uid].length === 0) { delete users[sessionID]; delete userSockets[uid]; if (uid) {