diff --git a/package.json b/package.json index 526d901336..167a504abf 100644 --- a/package.json +++ b/package.json @@ -48,9 +48,9 @@ "nodebb-plugin-soundpack-default": "0.1.4", "nodebb-plugin-spam-be-gone": "0.4.2", "nodebb-rewards-essentials": "0.0.5", - "nodebb-theme-lavender": "2.0.10", - "nodebb-theme-persona": "3.0.62", - "nodebb-theme-vanilla": "4.0.29", + "nodebb-theme-lavender": "2.0.11", + "nodebb-theme-persona": "3.0.68", + "nodebb-theme-vanilla": "4.0.32", "nodebb-widget-essentials": "2.0.3", "npm": "^2.1.4", "passport": "^0.3.0", @@ -67,7 +67,7 @@ "socket.io-redis": "^0.1.3", "socketio-wildcard": "~0.1.1", "string": "^3.0.0", - "templates.js": "0.3.0", + "templates.js": "0.2.16", "uglify-js": "^2.4.24", "underscore": "~1.8.3", "underscore.deep": "^0.5.1", diff --git a/public/language/en_GB/groups.json b/public/language/en_GB/groups.json index d800d74b1c..fcd15e21c6 100644 --- a/public/language/en_GB/groups.json +++ b/public/language/en_GB/groups.json @@ -19,8 +19,6 @@ "request.notification_title": "Group Membership Request from %1", "request.notification_text": "%1 has requested to become a member of %2", - "cover-instructions": "Drag and Drop a photo, drag to position, and hit Save", - "cover-change": "Change", "cover-save": "Save", "cover-saving": "Saving", diff --git a/public/less/admin/general/navigation.less b/public/less/admin/general/navigation.less index bb3efac15b..65828a2be3 100644 --- a/public/less/admin/general/navigation.less +++ b/public/less/admin/general/navigation.less @@ -1,9 +1,7 @@ - - #navigation { - - #active-navigation { + width: 100%; + .active { background-color: #eee; } @@ -17,6 +15,13 @@ .drag-item { cursor: move; margin-right: 10px; + padding: 8px 10px; + margin-bottom: 5px; + } + + p { + line-height: 20px; + min-height: 40px; } } @@ -33,5 +38,4 @@ list-style-type: none; padding: 0; } -} - +} \ No newline at end of file diff --git a/public/src/client/account/profile.js b/public/src/client/account/profile.js index 5a7756cc93..deffc3ab9a 100644 --- a/public/src/client/account/profile.js +++ b/public/src/client/account/profile.js @@ -2,7 +2,14 @@ /* globals define, ajaxify, app, utils, socket, bootbox */ -define('forum/account/profile', ['forum/account/header', 'forum/infinitescroll', 'translator'], function(header, infinitescroll, translator) { +define('forum/account/profile', [ + 'forum/account/header', + 'forum/infinitescroll', + 'translator', + 'coverPhoto', + 'uploader', + 'components' +], function(header, infinitescroll, translator, coverPhoto, uploader, components) { var Account = {}, yourid, theirid, @@ -41,6 +48,10 @@ define('forum/account/profile', ['forum/account/header', 'forum/infinitescroll', socket.on('event:user_status_change', onUserStatusChange); infinitescroll.init(loadMorePosts); + + if (parseInt(yourid, 10) === parseInt(theirid, 10)) { + setupCoverPhoto(); + } }; function processPage() { @@ -161,5 +172,22 @@ define('forum/account/profile', ['forum/account/header', 'forum/infinitescroll', }); } + function setupCoverPhoto() { + coverPhoto.init(components.get('account/cover'), + function(imageData, position, callback) { + socket.emit('user.updateCover', { + uid: yourid, + imageData: imageData, + position: position + }, callback); + }, + function() { + uploader.open(RELATIVE_PATH + '/api/user/uploadcover', { uid: yourid }, 0, function(imageUrlOnServer) { + components.get('account/cover').css('background-image', 'url(' + imageUrlOnServer + ')'); + }); + } + ); + } + return Account; }); diff --git a/public/src/client/groups/details.js b/public/src/client/groups/details.js index be624b2160..2169fd07f5 100644 --- a/public/src/client/groups/details.js +++ b/public/src/client/groups/details.js @@ -1,18 +1,16 @@ "use strict"; -/* globals define, socket, ajaxify, app, bootbox, utils */ +/* globals define, socket, ajaxify, app, bootbox, utils, RELATIVE_PATH */ define('forum/groups/details', [ 'forum/groups/memberlist', 'iconSelect', 'components', - 'vendor/colorpicker/colorpicker', - 'vendor/jquery/draggable-background/backgroundDraggable' -], function(memberList, iconSelect, components) { - - var Details = { - cover: {} - }; + 'coverPhoto', + 'uploader', + 'vendor/colorpicker/colorpicker' +], function(memberList, iconSelect, components, coverPhoto, uploader) { + var Details = {}; var groupName; Details.init = function() { @@ -22,7 +20,21 @@ define('forum/groups/details', [ if (ajaxify.data.group.isOwner) { Details.prepareSettings(); - Details.initialiseCover(); + + coverPhoto.init(components.get('groups/cover'), + function(imageData, position, callback) { + socket.emit('groups.cover.update', { + groupName: groupName, + imageData: imageData, + position: position + }, callback); + }, + function() { + uploader.open(RELATIVE_PATH + '/api/groups/uploadpicture', { groupName: groupName }, 0, function(imageUrlOnServer) { + components.get('groups/cover').css('background-image', 'url(' + imageUrlOnServer + ')'); + }); + } + ); } memberList.init(); @@ -209,93 +221,6 @@ define('forum/groups/details', [ }); }; - // Cover Photo Handling Code - - Details.initialiseCover = function() { - var coverEl = components.get('groups/cover'); - coverEl.find('.change').on('click', function() { - coverEl.toggleClass('active', 1); - coverEl.backgroundDraggable({ - axis: 'y', - units: 'percent' - }); - coverEl.on('dragover', Details.cover.onDragOver); - coverEl.on('drop', Details.cover.onDrop); - }); - - coverEl.find('.save').on('click', Details.cover.save); - coverEl.addClass('initialised'); - }; - - Details.cover.load = function() { - socket.emit('groups.cover.get', { - groupName: groupName - }, function(err, data) { - if (!err) { - var coverEl = components.get('groups/cover'); - if (data['cover:url']) { - coverEl.css('background-image', 'url(' + data['cover:url'] + ')'); - } - - if (data['cover:position']) { - coverEl.css('background-position', data['cover:position']); - } - - delete Details.cover.newCover; - } else { - app.alertError(err.message); - } - }); - }; - - Details.cover.onDragOver = function(e) { - e.stopPropagation(); - e.preventDefault(); - e.originalEvent.dataTransfer.dropEffect = 'copy'; - }; - - Details.cover.onDrop = function(e) { - var coverEl = components.get('groups/cover'); - e.stopPropagation(); - e.preventDefault(); - - var files = e.originalEvent.dataTransfer.files, - reader = new FileReader(); - - if (files.length && files[0].type.match('image.*')) { - reader.onload = function(e) { - coverEl.css('background-image', 'url(' + e.target.result + ')'); - Details.cover.newCover = e.target.result; - }; - - reader.readAsDataURL(files[0]); - } - }; - - Details.cover.save = function() { - var coverEl = components.get('groups/cover'); - - coverEl.addClass('saving'); - - socket.emit('groups.cover.update', { - groupName: groupName, - imageData: Details.cover.newCover || undefined, - position: components.get('groups/cover').css('background-position') - }, function(err) { - if (!err) { - coverEl.toggleClass('active', 0); - coverEl.backgroundDraggable('disable'); - coverEl.off('dragover', Details.cover.onDragOver); - coverEl.off('drop', Details.cover.onDrop); - Details.cover.load(); - } else { - app.alertError(err.message); - } - - coverEl.removeClass('saving'); - }); - }; - function handleMemberInvitations() { if (ajaxify.data.group.isOwner) { var searchInput = $('[component="groups/members/invite"]'); diff --git a/public/src/client/topic.js b/public/src/client/topic.js index faaaddbf00..c216943e32 100644 --- a/public/src/client/topic.js +++ b/public/src/client/topic.js @@ -18,6 +18,11 @@ define('forum/topic', [ currentUrl = ''; $(window).on('action:ajaxify.start', function(ev, data) { + if (Topic.replaceURLTimeout) { + clearTimeout(Topic.replaceURLTimeout); + Topic.replaceURLTimeout = 0; + } + if (ajaxify.currentPage !== data.url) { navigator.disable(); components.get('navbar/title').find('span').text('').hide(); diff --git a/public/src/client/topic/events.js b/public/src/client/topic/events.js index 7dfe57beed..7e04a5ffae 100644 --- a/public/src/client/topic/events.js +++ b/public/src/client/topic/events.js @@ -118,6 +118,7 @@ define('forum/topic/events', [ editedPostEl.html(data.post.content); editedPostEl.find('img:not(.not-responsive)').addClass('img-responsive'); app.replaceSelfLinks(editedPostEl.find('a')); + posts.wrapImagesInLinks(editedPostEl.parent()); editedPostEl.fadeIn(250); $(window).trigger('action:posts.edited', data); }); diff --git a/public/src/client/topic/posts.js b/public/src/client/topic/posts.js index 02fdfbc26f..89c9e70e1d 100644 --- a/public/src/client/topic/posts.js +++ b/public/src/client/topic/posts.js @@ -217,15 +217,19 @@ define('forum/topic/posts', [ utils.addCommasToNumbers(posts.find('.formatted-number')); utils.makeNumbersHumanReadable(posts.find('.human-readable-number')); posts.find('.timeago').timeago(); + Posts.wrapImagesInLinks(posts); + + addBlockquoteEllipses(posts.find('[component="post/content"] > blockquote > blockquote')); + hidePostToolsForDeletedPosts(posts); + }; + + Posts.wrapImagesInLinks = function(posts) { posts.find('[component="post/content"] img:not(.emoji)').each(function() { var $this = $(this); if (!$this.parent().is('a')) { $this.wrap(''); } }); - - addBlockquoteEllipses(posts.find('[component="post/content"] > blockquote > blockquote')); - hidePostToolsForDeletedPosts(posts); }; Posts.showBottomPostBar = function() { diff --git a/public/src/modules/coverPhoto.js b/public/src/modules/coverPhoto.js new file mode 100644 index 0000000000..3d36d6d710 --- /dev/null +++ b/public/src/modules/coverPhoto.js @@ -0,0 +1,83 @@ +"use strict"; +/* globals define, app */ + +define('coverPhoto', [ + 'vendor/jquery/draggable-background/backgroundDraggable' +], function() { + + var coverPhoto = { + coverEl: null, + saveFn: null + }; + + coverPhoto.init = function(coverEl, saveFn, uploadFn) { + coverPhoto.coverEl = coverEl; + coverPhoto.saveFn = saveFn; + + coverEl.find('.upload').on('click', uploadFn); + coverEl.find('.resize').on('click', function() { + coverEl + .toggleClass('active', 1) + .backgroundDraggable({ + axis: 'y', + units: 'percent' + }); + }); + + coverEl + .on('dragover', coverPhoto.onDragOver) + .on('drop', coverPhoto.onDrop); + + coverEl.find('.save').on('click', coverPhoto.save); + coverEl.addClass('initialised'); + }; + + coverPhoto.onDragOver = function(e) { + e.stopPropagation(); + e.preventDefault(); + e.originalEvent.dataTransfer.dropEffect = 'copy'; + }; + + coverPhoto.onDrop = function(e) { + e.stopPropagation(); + e.preventDefault(); + + var files = e.originalEvent.dataTransfer.files, + reader = new FileReader(); + + if (files.length && files[0].type.match('image.*')) { + reader.onload = function(e) { + coverPhoto.coverEl.css('background-image', 'url(' + e.target.result + ')'); + coverPhoto.newCover = e.target.result; + }; + + reader.readAsDataURL(files[0]); + + coverPhoto.coverEl + .addClass('active', 1) + .backgroundDraggable({ + axis: 'y', + units: 'percent' + }); + } + }; + + coverPhoto.save = function() { + coverPhoto.coverEl.addClass('saving'); + + coverPhoto.saveFn(coverPhoto.newCover || undefined, coverPhoto.coverEl.css('background-position'), function(err) { + if (!err) { + coverPhoto.coverEl.toggleClass('active', 0); + coverPhoto.coverEl.backgroundDraggable('disable'); + coverPhoto.coverEl.off('dragover', coverPhoto.onDragOver); + coverPhoto.coverEl.off('drop', coverPhoto.onDrop); + } else { + app.alertError(err.message); + } + + coverPhoto.coverEl.removeClass('saving'); + }); + }; + + return coverPhoto; +}); \ No newline at end of file diff --git a/src/controllers/accounts/edit.js b/src/controllers/accounts/edit.js index a84dc7c991..0205b60356 100644 --- a/src/controllers/accounts/edit.js +++ b/src/controllers/accounts/edit.js @@ -120,4 +120,19 @@ editController.uploadPicture = function (req, res, next) { }); }; +editController.uploadCoverPicture = function(req, res, next) { + var params = JSON.parse(req.body.params); + + user.updateCoverPicture({ + file: req.files.files[0].path, + uid: params.uid + }, function(err, image) { + if (err) { + return next(err); + } + + res.json([{url: image.url.startsWith('http') ? image.url : nconf.get('relative_path') + image.url}]); + }); +}; + module.exports = editController; \ No newline at end of file diff --git a/src/controllers/accounts/helpers.js b/src/controllers/accounts/helpers.js index 9a881ddab5..63a25a992a 100644 --- a/src/controllers/accounts/helpers.js +++ b/src/controllers/accounts/helpers.js @@ -3,6 +3,7 @@ var async = require('async'), validator = require('validator'), + nconf = require('nconf'), user = require('../../user'), groups = require('../../groups'), @@ -118,7 +119,7 @@ helpers.getBaseUser = function(userslug, callerUID, callback) { async.parallel({ user: function(next) { - user.getUserFields(uid, ['uid', 'username', 'userslug'], next); + user.getUserFields(uid, ['uid', 'username', 'userslug', 'picture', 'cover:url', 'cover:position'], next); }, isAdmin: function(next) { user.isAdministrator(callerUID, next); @@ -138,6 +139,10 @@ helpers.getBaseUser = function(userslug, callerUID, callback) { results.user.isSelf = parseInt(callerUID, 10) === parseInt(results.user.uid, 10); results.user.showHidden = results.user.isSelf || results.isAdmin; results.user.profile_links = results.profile_links; + + results['cover:url'] = results['cover:url'] || nconf.get('relative_path') + '/images/cover-default.png'; + results['cover:position'] = results['cover:position'] || '50% 50%'; + next(null, results.user); } ], callback); diff --git a/src/controllers/api.js b/src/controllers/api.js index 421673e7c4..9a6fbee238 100644 --- a/src/controllers/api.js +++ b/src/controllers/api.js @@ -112,13 +112,11 @@ apiController.getConfig = function(req, res, next) { apiController.renderWidgets = function(req, res, next) { - var async = require('async'), - areas = { - template: req.query.template, - locations: req.query.locations, - url: req.query.url - }, - renderedWidgets = []; + var areas = { + template: req.query.template, + locations: req.query.locations, + url: req.query.url + }; if (!areas.template || !areas.locations) { return res.status(200).json({}); diff --git a/src/controllers/groups.js b/src/controllers/groups.js index 7d37a5ca2a..111d41a752 100644 --- a/src/controllers/groups.js +++ b/src/controllers/groups.js @@ -3,7 +3,6 @@ var async = require('async'), nconf = require('nconf'), validator = require('validator'), - db = require('../database'), meta = require('../meta'), groups = require('../groups'), user = require('../user'), @@ -132,4 +131,19 @@ groupsController.members = function(req, res, next) { }); }; +groupsController.uploadCover = function(req, res, next) { + var params = JSON.parse(req.body.params); + + groups.updateCover({ + file: req.files.files[0].path, + groupName: params.groupName + }, function(err, image) { + if (err) { + return next(err); + } + + res.json([{url: image.url.startsWith('http') ? image.url : nconf.get('relative_path') + image.url}]); + }); +}; + module.exports = groupsController; diff --git a/src/controllers/uploads.js b/src/controllers/uploads.js index 491553fb24..d798524f3e 100644 --- a/src/controllers/uploads.js +++ b/src/controllers/uploads.js @@ -93,7 +93,11 @@ uploadsController.uploadThumb = function(req, res, next) { }; uploadsController.uploadGroupCover = function(data, next) { - uploadImage(0/*req.user.uid*/, data, next); + uploadImage(0, data, next); +}; + +uploadsController.uploadUserCover = function(data, next) { + uploadImage(data.uid, data, next); }; function uploadImage(uid, image, callback) { diff --git a/src/groups/update.js b/src/groups/update.js index 595a839ed7..a92ed3bc2b 100644 --- a/src/groups/update.js +++ b/src/groups/update.js @@ -104,9 +104,7 @@ module.exports = function(Groups) { async.parallel([ async.apply(db.setObjectField, 'group:' + groupName, 'hidden', hidden ? 1 : 0), async.apply(updateVisibility, groupName, hidden) - ], function(err, results) { - callback(err); - }); + ], callback); } Groups.updateCoverPosition = function(groupName, position, callback) { @@ -123,6 +121,10 @@ module.exports = function(Groups) { async.series([ function(next) { + if (data.file) { + return next(); + } + // Calculate md5sum of image // This is required because user data can be private md5sum = crypto.createHash('md5'); @@ -131,6 +133,10 @@ module.exports = function(Groups) { next(); }, function(next) { + if (data.file) { + return next(); + } + // Save image tempPath = path.join(nconf.get('base_dir'), nconf.get('upload_path'), md5sum); var buffer = new Buffer(data.imageData.slice(data.imageData.indexOf('base64') + 7), 'base64'); @@ -142,7 +148,7 @@ module.exports = function(Groups) { function(next) { uploadsController.uploadGroupCover({ name: 'groupCover', - path: tempPath + path: data.file ? data.file : tempPath }, function(err, uploadData) { if (err) { return next(err); @@ -156,14 +162,20 @@ module.exports = function(Groups) { Groups.setGroupField(data.groupName, 'cover:url', url, next); }, function(next) { - fs.unlink(tempPath, next); // Delete temporary file + fs.unlink(data.file ? data.file : tempPath, next); // Delete temporary file } ], function(err) { if (err) { return callback(err); } - Groups.updateCoverPosition(data.groupName, data.position, callback); + if (data.position) { + Groups.updateCoverPosition(data.groupName, data.position, function(err) { + callback(err, {url: url}); + }); + } else { + callback(err, {url: url}); + } }); }; diff --git a/src/middleware/admin.js b/src/middleware/admin.js index 0dd81dc8fe..27c58bed83 100644 --- a/src/middleware/admin.js +++ b/src/middleware/admin.js @@ -4,7 +4,6 @@ var app, middleware = {}, nconf = require('nconf'), async = require('async'), - path = require('path'), winston = require('winston'), user = require('../user'), meta = require('../meta'), @@ -95,6 +94,12 @@ middleware.renderHeader = function(req, res, data, next) { } res.locals.config = results.config; + var acpPath = req.path.slice(1).split('/'); + acpPath.forEach(function(path, i) { + acpPath[i] = path.charAt(0).toUpperCase() + path.slice(1); + }); + acpPath = acpPath.join(' > '); + var templateValues = { config: results.config, configJSON: JSON.stringify(results.config), @@ -106,7 +111,8 @@ middleware.renderHeader = function(req, res, data, next) { authentication: results.custom_header.authentication, scripts: results.scripts, 'cache-buster': meta.config['cache-buster'] ? 'v=' + meta.config['cache-buster'] : '', - env: process.env.NODE_ENV ? true : false + env: process.env.NODE_ENV ? true : false, + title: acpPath + ' | NodeBB Admin Control Panel' }; templateValues.template = {name: res.locals.template}; diff --git a/src/posts/edit.js b/src/posts/edit.js index 2eca8a8328..ea7686fb20 100644 --- a/src/posts/edit.js +++ b/src/posts/edit.js @@ -86,7 +86,7 @@ module.exports = function(Posts) { function editMainPost(data, postData, callback) { var tid = postData.tid; - var title = data.title.trim(); + var title = data.title ? data.title.trim() : ''; async.parallel({ topic: function(next) { diff --git a/src/privileges/categories.js b/src/privileges/categories.js index 31d1deeeb3..d51edbb9a8 100644 --- a/src/privileges/categories.js +++ b/src/privileges/categories.js @@ -191,6 +191,9 @@ module.exports = function(privileges) { }; privileges.categories.isAdminOrMod = function(cid, uid, callback) { + if (!parseInt(uid, 10)) { + return callback(null, false); + } helpers.some([ function (next) { user.isModerator(uid, cid, next); diff --git a/src/routes/api.js b/src/routes/api.js index a888c20747..32d764f5de 100644 --- a/src/routes/api.js +++ b/src/routes/api.js @@ -28,5 +28,8 @@ module.exports = function(app, middleware, controllers) { router.post('/post/upload', middlewares, uploadsController.uploadPost); router.post('/topic/thumb/upload', middlewares, uploadsController.uploadThumb); router.post('/user/:userslug/uploadpicture', middlewares.concat([middleware.authenticate, middleware.checkGlobalPrivacySettings, middleware.checkAccountPermissions]), controllers.accounts.edit.uploadPicture); + + router.post('/user/uploadcover', middlewares.concat([middleware.authenticate, middleware.checkGlobalPrivacySettings, middleware.checkAccountPermissions]), controllers.accounts.edit.uploadCoverPicture); + router.post('/groups/uploadpicture', middlewares.concat([middleware.authenticate]), controllers.groups.uploadCover); }; diff --git a/src/socket.io/groups.js b/src/socket.io/groups.js index 9807e821b8..d5d2cc926f 100644 --- a/src/socket.io/groups.js +++ b/src/socket.io/groups.js @@ -228,10 +228,6 @@ SocketGroups.loadMoreMembers = function(socket, data, callback) { SocketGroups.cover = {}; -SocketGroups.cover.get = function(socket, data, callback) { - groups.getGroupFields(data.groupName, ['cover:url', 'cover:position'], callback); -}; - SocketGroups.cover.update = function(socket, data, callback) { if (!socket.uid) { return callback(new Error('[[error:no-privileges]]')); diff --git a/src/socket.io/posts/tools.js b/src/socket.io/posts/tools.js index fc4491ea44..5830820cb6 100644 --- a/src/socket.io/posts/tools.js +++ b/src/socket.io/posts/tools.js @@ -7,17 +7,14 @@ var events = require('../../events'); var websockets = require('../index'); var socketTopics = require('../topics'); var privileges = require('../../privileges'); +var plugins = require('../../plugins'); var favourites = require('../../favourites'); - module.exports = function(SocketPosts) { SocketPosts.loadPostTools = function(socket, data, callback) { - if (!socket.uid) { - return; - } if (!data) { - return callback(new Error('[[error:invalid-data]]')) + return callback(new Error('[[error:invalid-data]]')); } async.parallel({ @@ -29,15 +26,18 @@ module.exports = function(SocketPosts) { }, favourited: function(next) { favourites.getFavouritesByPostIDs([data.pid], socket.uid, next); + }, + tools: function(next) { + plugins.fireHook('filter:post.tools', {pid: data.pid, uid: socket.uid, tools: []}, next); } }, function(err, results) { if (err) { return callback(err); } - results.posts.tools = []; // TODO: add filter for this + results.posts.tools = results.tools.tools; results.posts.deleted = parseInt(results.posts.deleted, 10) === 1; results.posts.favourited = results.favourited[0]; - results.posts.selfPost = socket.uid === parseInt(results.posts.uid, 10); + results.posts.selfPost = socket.uid && socket.uid === parseInt(results.posts.uid, 10); results.posts.display_moderator_tools = results.isAdminOrMod || results.posts.selfPost; results.posts.display_move_tools = results.isAdminOrMod; callback(null, results); diff --git a/src/socket.io/user/profile.js b/src/socket.io/user/profile.js index 4e0be0acc5..4eccfbcfe5 100644 --- a/src/socket.io/user/profile.js +++ b/src/socket.io/user/profile.js @@ -23,6 +23,20 @@ module.exports = function(SocketUser) { ], callback); }; + SocketUser.updateCover = function(socket, data, callback) { + if (!socket.uid) { + return callback(new Error('[[error:no-privileges]]')); + } + + user.isAdministrator(socket.uid, function(err, isAdmin) { + if (!isAdmin && data.uid !== socket.uid) { + return callback(new Error('[[error:no-privileges]]')); + } + + user.updateCoverPicture(data, callback); + }); + }; + function isAdminOrSelfAndPasswordMatch(uid, data, callback) { async.parallel({ isAdmin: async.apply(user.isAdministrator, uid), diff --git a/src/user/picture.js b/src/user/picture.js index cf89f34399..20bb9647ef 100644 --- a/src/user/picture.js +++ b/src/user/picture.js @@ -4,10 +4,12 @@ var async = require('async'), path = require('path'), fs = require('fs'), nconf = require('nconf'), + crypto = require('crypto'), winston = require('winston'), request = require('request'), mime = require('mime'), + uploadsController = require('../controllers/uploads'), plugins = require('../plugins'), file = require('../file'), image = require('../image'), @@ -51,7 +53,7 @@ module.exports = function(User) { next(); } } - ], function(err, result) { + ], function(err) { function done(err, image) { if (err) { return callback(err); @@ -99,7 +101,7 @@ module.exports = function(User) { return callback(new Error('[[error:no-plugin]]')); } - request.head(url, function(err, res, body) { + request.head(url, function(err, res) { if (err) { return callback(err); } @@ -126,4 +128,74 @@ module.exports = function(User) { }); }); }; + + User.updateCoverPosition = function(uid, position, callback) { + User.setUserField(uid, 'cover:position', position, callback); + }; + + User.updateCoverPicture = function(data, callback) { + var tempPath, url, md5sum; + + if (!data.imageData && data.position) { + return User.updateCoverPosition(data.uid, data.position, callback); + } + + async.series([ + function(next) { + if (data.file) { + return next(); + } + + md5sum = crypto.createHash('md5'); + md5sum.update(data.imageData); + md5sum = md5sum.digest('hex'); + next(); + }, + function(next) { + if (data.file) { + return next(); + } + + tempPath = path.join(nconf.get('base_dir'), nconf.get('upload_path'), md5sum); + var buffer = new Buffer(data.imageData.slice(data.imageData.indexOf('base64') + 7), 'base64'); + + fs.writeFile(tempPath, buffer, { + encoding: 'base64' + }, next); + }, + function(next) { + uploadsController.uploadUserCover({ + name: 'profileCover', + path: data.file ? data.file : tempPath, + uid: data.uid + }, function(err, uploadData) { + if (err) { + return next(err); + } + + url = uploadData.url; + next(); + }); + }, + function(next) { + User.setUserField(data.uid, 'cover:url', url, next); + }, + function(next) { + require('fs').unlink(data.file ? data.file : tempPath, next); + } + ], function(err) { + if (err) { + return callback(err); + } + + if (data.position) { + User.updateCoverPosition(data.uid, data.position, function(err) { + callback(err, {url: url}); + }); + } else { + callback(err, {url: url}); + } + }); + }; + }; \ No newline at end of file diff --git a/src/views/admin/general/navigation.tpl b/src/views/admin/general/navigation.tpl index ba7f5942e5..826960e569 100644 --- a/src/views/admin/general/navigation.tpl +++ b/src/views/admin/general/navigation.tpl @@ -1,107 +1,99 @@
@@ -110,14 +102,16 @@