From e5e41e85f2dd040fd364f636041c414f581eaaa1 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Fri, 25 Sep 2015 13:11:11 -0400 Subject: [PATCH] accounts refactor #2 and various 404 fixes --- package.json | 2 +- src/controllers/accounts.js | 449 +--------------------- src/controllers/accounts/chats.js | 91 +++++ src/controllers/accounts/edit.js | 47 +++ src/controllers/accounts/follow.js | 48 +++ src/controllers/accounts/groups.js | 54 +++ src/controllers/accounts/helpers.js | 38 ++ src/controllers/accounts/notifications.js | 23 ++ src/controllers/accounts/posts.js | 84 ++++ src/controllers/accounts/settings.js | 107 ++++++ src/controllers/api.js | 36 ++ src/routes/accounts.js | 20 +- src/routes/api.js | 24 +- 13 files changed, 551 insertions(+), 472 deletions(-) create mode 100644 src/controllers/accounts/chats.js create mode 100644 src/controllers/accounts/follow.js create mode 100644 src/controllers/accounts/groups.js create mode 100644 src/controllers/accounts/notifications.js create mode 100644 src/controllers/accounts/posts.js create mode 100644 src/controllers/accounts/settings.js diff --git a/package.json b/package.json index 0da7ec714f..bbe4d7087f 100644 --- a/package.json +++ b/package.json @@ -49,7 +49,7 @@ "nodebb-plugin-spam-be-gone": "0.4.2", "nodebb-rewards-essentials": "0.0.5", "nodebb-theme-lavender": "2.0.2", - "nodebb-theme-persona": "3.0.19", + "nodebb-theme-persona": "3.0.21", "nodebb-theme-vanilla": "4.0.12", "nodebb-widget-essentials": "2.0.1", "npm": "^2.1.4", diff --git a/src/controllers/accounts.js b/src/controllers/accounts.js index 9dd7ffe902..8384b4e9b8 100644 --- a/src/controllers/accounts.js +++ b/src/controllers/accounts.js @@ -1,448 +1,15 @@ -"use strict"; - - - -var fs = require('fs'), - nconf = require('nconf'), - async = require('async'), - validator = require('validator'), - winston = require('winston'), - - db = require('../database'), - user = require('../user'), - posts = require('../posts'), - topics = require('../topics'), - groups = require('../groups'), - messaging = require('../messaging'), - utils = require('../../public/src/utils'), - meta = require('../meta'), - plugins = require('../plugins'), - languages = require('../languages'), - - helpers = require('./helpers'); - +'use strict'; var accountsController = { profile: require('./accounts/profile'), - edit: require('./accounts/edit') -}; - - -accountsController.getUserByUID = function(req, res, next) { - var uid = req.params.uid ? req.params.uid : 0; - - async.parallel({ - userData: async.apply(user.getUserData, uid), - settings: async.apply(user.getSettings, uid) - }, function(err, results) { - if (err || !results.userData) { - return next(err); - } - - results.userData.email = results.settings.showemail ? results.userData.email : undefined; - results.userData.fullname = results.settings.showfullname ? results.userData.fullname : undefined; - - res.json(results.userData); - }); -}; - - -accountsController.getFollowing = function(req, res, next) { - getFollow('account/following', 'following', req, res, next); + edit: require('./accounts/edit'), + settings: require('./accounts/settings'), + groups: require('./accounts/groups'), + follow: require('./accounts/follow'), + posts: require('./accounts/posts'), + notifications: require('./accounts/notifications'), + chats: require('./accounts/chats') }; -accountsController.getFollowers = function(req, res, next) { - getFollow('account/followers', 'followers', req, res, next); -}; - -function getFollow(tpl, name, req, res, callback) { - var userData; - - async.waterfall([ - function(next) { - accountsController.getBaseUser(req.params.userslug, req.uid, next); - }, - function(data, next) { - userData = data; - if (!userData) { - return callback(); - } - var method = name === 'following' ? 'getFollowing' : 'getFollowers'; - user[method](userData.uid, 0, 49, next); - } - ], function(err, users) { - if (err) { - return callback(err); - } - - userData.users = users; - userData.nextStart = 50; - userData.title = '[[pages:' + tpl + ', ' + userData.username + ']]'; - userData.breadcrumbs = helpers.buildBreadcrumbs([{text: userData.username, url: '/user/' + userData.userslug}, {text: '[[user:' + name + ']]'}]); - - res.render(tpl, userData); - }); -} - -accountsController.getFavourites = function(req, res, next) { - getFromUserSet('account/favourites', 'favourites', '[[user:favourites]]', posts.getPostSummariesFromSet, 'posts', req, res, next); -}; - -accountsController.getPosts = function(req, res, next) { - getFromUserSet('account/posts', 'posts', '[[global:posts]]', posts.getPostSummariesFromSet, 'posts', req, res, next); -}; - -accountsController.getWatchedTopics = function(req, res, next) { - getFromUserSet('account/watched', 'followed_tids', '[[user:watched]]',topics.getTopicsFromSet, 'topics', req, res, next); -}; - -accountsController.getTopics = function(req, res, next) { - getFromUserSet('account/topics', 'topics', '[[global:topics]]', topics.getTopicsFromSet, 'topics', req, res, next); -}; - -accountsController.getGroups = function(req, res, next) { - var userData; - var groupsData; - async.waterfall([ - function (next) { - accountsController.getBaseUser(req.params.userslug, req.uid, next); - }, - function (_userData, next) { - userData = _userData; - - groups.getUserGroups([userData.uid], next); - }, - function (_groupsData, next) { - groupsData = _groupsData[0]; - var groupNames = groupsData.map(function(group) { - return group.name; - }); - - groups.getMemberUsers(groupNames, 0, 3, next); - }, - function (members, next) { - groupsData.forEach(function(group, index) { - group.members = members[index]; - }); - next(); - } - ], function(err) { - if (err) { - return next(err); - } - - userData.groups = groupsData; - userData.title = '[[pages:account/groups, ' + userData.username + ']]'; - userData.breadcrumbs = helpers.buildBreadcrumbs([{text: userData.username, url: '/user/' + userData.userslug}, {text: '[[global:header.groups]]'}]); - res.render('account/groups', userData); - }); -}; - -function getFromUserSet(tpl, set, crumb, method, type, req, res, next) { - async.parallel({ - settings: function(next) { - user.getSettings(req.uid, next); - }, - userData: function(next) { - accountsController.getBaseUser(req.params.userslug, req.uid, next); - } - }, function(err, results) { - if (err || !results.userData) { - return next(err); - } - - var userData = results.userData; - - var setName = 'uid:' + userData.uid + ':' + set; - - var page = Math.max(1, parseInt(req.query.page, 10) || 1); - var itemsPerPage = (tpl === 'account/topics' || tpl === 'account/watched') ? results.settings.topicsPerPage : results.settings.postsPerPage; - - async.parallel({ - itemCount: function(next) { - if (results.settings.usePagination) { - db.sortedSetCard(setName, next); - } else { - next(null, 0); - } - }, - data: function(next) { - var start = (page - 1) * itemsPerPage; - var stop = start + itemsPerPage - 1; - method(setName, req.uid, start, stop, next); - } - }, function(err, results) { - if (err) { - return next(err); - } - - userData[type] = results.data[type]; - userData.nextStart = results.data.nextStart; - var pageCount = Math.ceil(results.itemCount / itemsPerPage); - - var pagination = require('../pagination'); - userData.pagination = pagination.create(page, pageCount); - - userData.title = '[[pages:' + tpl + ', ' + userData.username + ']]'; - userData.breadcrumbs = helpers.buildBreadcrumbs([{text: userData.username, url: '/user/' + userData.userslug}, {text: crumb}]); - - res.render(tpl, userData); - }); - }); -} - -accountsController.getBaseUser = function(userslug, callerUID, callback) { - user.getUidByUserslug(userslug, function (err, uid) { - if (err || !uid) { - return callback(err); - } - - async.parallel({ - user: function(next) { - user.getUserFields(uid, ['uid', 'username', 'userslug'], next); - }, - isAdmin: function(next) { - user.isAdministrator(callerUID, next); - }, - profile_links: function(next) { - plugins.fireHook('filter:user.profileLinks', [], next); - } - }, function(err, results) { - if (err) { - return callback(err); - } - - if (!results.user) { - return callback(); - } - - results.user.yourid = callerUID; - results.user.theirid = uid; - results.user.isSelf = parseInt(callerUID, 10) === parseInt(uid, 10); - results.user.showHidden = results.user.isSelf || results.isAdmin; - results.user.profile_links = results.profile_links; - callback(null, results.user); - }); - }); -}; - -accountsController.accountSettings = function(req, res, callback) { - var userData; - async.waterfall([ - function(next) { - accountsController.getBaseUser(req.params.userslug, req.uid, next); - }, - function(_userData, next) { - userData = _userData; - if (!userData) { - return callback(); - } - async.parallel({ - settings: function(next) { - user.getSettings(userData.uid, next); - }, - userGroups: function(next) { - groups.getUserGroups([userData.uid], next); - }, - languages: function(next) { - languages.list(next); - } - }, next); - }, - function(results, next) { - userData.settings = results.settings; - userData.languages = results.languages; - userData.userGroups = results.userGroups[0]; - plugins.fireHook('filter:user.customSettings', {settings: results.settings, customSettings: [], uid: req.uid}, next); - }, - function(data, next) { - userData.customSettings = data.customSettings; - userData.disableEmailSubscriptions = parseInt(meta.config.disableEmailSubscriptions, 10) === 1; - next(); - } - ], function(err) { - if (err) { - return callback(err); - } - - userData.dailyDigestFreqOptions = [ - {value: 'off', name: '[[user:digest_off]]', selected: 'off' === userData.settings.dailyDigestFreq}, - {value: 'day', name: '[[user:digest_daily]]', selected: 'day' === userData.settings.dailyDigestFreq}, - {value: 'week', name: '[[user:digest_weekly]]', selected: 'week' === userData.settings.dailyDigestFreq}, - {value: 'month', name: '[[user:digest_monthly]]', selected: 'month' === userData.settings.dailyDigestFreq} - ]; - - - userData.bootswatchSkinOptions = [ - { "name": "Default", "value": "default" }, - { "name": "Cerulean", "value": "cerulean" }, - { "name": "Cosmo", "value": "cosmo" }, - { "name": "Cyborg", "value": "cyborg" }, - { "name": "Darkly", "value": "darkly" }, - { "name": "Flatly", "value": "flatly" }, - { "name": "Journal", "value": "journal" }, - { "name": "Lumen", "value": "lumen" }, - { "name": "Paper", "value": "paper" }, - { "name": "Readable", "value": "readable" }, - { "name": "Sandstone", "value": "sandstone" }, - { "name": "Simplex", "value": "simplex" }, - { "name": "Slate", "value": "slate" }, - { "name": "Spacelab", "value": "spacelab" }, - { "name": "Superhero", "value": "superhero" }, - { "name": "United", "value": "united" }, - { "name": "Yeti", "value": "yeti" } - ]; - - userData.bootswatchSkinOptions.forEach(function(skin) { - skin.selected = skin.value === userData.settings.bootswatchSkin; - }); - - userData.userGroups.forEach(function(group) { - group.selected = group.name === userData.settings.groupTitle; - }); - - userData.languages.forEach(function(language) { - language.selected = language.code === userData.settings.userLang; - }); - - userData.disableCustomUserSkins = parseInt(meta.config.disableCustomUserSkins, 10) === 1; - - userData.title = '[[pages:account/settings]]'; - userData.breadcrumbs = helpers.buildBreadcrumbs([{text: userData.username, url: '/user/' + userData.userslug}, {text: '[[user:settings]]'}]); - - res.render('account/settings', userData); - }); -}; - -accountsController.uploadPicture = function (req, res, next) { - var userPhoto = req.files.files[0]; - - var updateUid = req.uid; - - async.waterfall([ - function(next) { - user.getUidByUserslug(req.params.userslug, next); - }, - function(uid, next) { - if (parseInt(updateUid, 10) === parseInt(uid, 10)) { - return next(); - } - - user.isAdministrator(req.uid, function(err, isAdmin) { - if (err) { - return next(err); - } - - if (!isAdmin) { - return helpers.notAllowed(req, res); - } - updateUid = uid; - next(); - }); - }, - function(next) { - user.uploadPicture(updateUid, userPhoto, next); - } - ], function(err, image) { - fs.unlink(userPhoto.path, function(err) { - winston.error('unable to delete picture ' + userPhoto.path, err); - }); - if (err) { - return next(err); - } - - res.json([{name: userPhoto.name, url: image.url.startsWith('http') ? image.url : nconf.get('relative_path') + image.url}]); - }); -}; - -accountsController.getNotifications = function(req, res, next) { - user.notifications.getAll(req.uid, 40, function(err, notifications) { - if (err) { - return next(err); - } - res.render('notifications', { - notifications: notifications, - title: '[[pages:notifications]]', - breadcrumbs: helpers.buildBreadcrumbs([{text: '[[pages:notifications]]'}]) - }); - }); -}; - -accountsController.getChats = function(req, res, callback) { - if (parseInt(meta.config.disableChat, 10) === 1) { - return callback(); - } - - // In case a userNAME is passed in instead of a slug, the route should not 404 - var slugified = utils.slugify(req.params.userslug); - if (req.params.userslug && req.params.userslug !== slugified) { - return res.redirect(nconf.get('relative_path') + '/chats/' + slugified); - } - - async.parallel({ - contacts: async.apply(user.getFollowing, req.user.uid, 0, 199), - recentChats: async.apply(messaging.getRecentChats, req.user.uid, 0, 19) - }, function(err, results) { - if (err) { - return callback(err); - } - - if (results.recentChats.users && results.recentChats.users.length) { - var contactUids = results.recentChats.users.map(function(chatObj) { - return parseInt(chatObj.uid, 10); - }); - - results.contacts = results.contacts.filter(function(contact) { - return contactUids.indexOf(parseInt(contact.uid, 10)) === -1; - }); - } - - if (!req.params.userslug) { - return res.render('chats', { - chats: results.recentChats.users, - nextStart: results.recentChats.nextStart, - contacts: results.contacts, - allowed: true, - title: '[[pages:chats]]', - breadcrumbs: helpers.buildBreadcrumbs([{text: '[[pages:chats]]'}]) - }); - } - - async.waterfall([ - async.apply(user.getUidByUserslug, req.params.userslug), - function(toUid, next) { - if (!toUid || parseInt(toUid, 10) === parseInt(req.user.uid, 10)) { - return callback(); - } - - async.parallel({ - toUser: async.apply(user.getUserFields, toUid, ['uid', 'username']), - messages: async.apply(messaging.getMessages, { - fromuid: req.user.uid, - touid: toUid, - since: 'recent', - isNew: false - }), - allowed: async.apply(messaging.canMessage, req.user.uid, toUid) - }, next); - } - ], function(err, data) { - if (err) { - return callback(err); - } - - res.render('chats', { - chats: results.recentChats.users, - nextStart: results.recentChats.nextStart, - contacts: results.contacts, - meta: data.toUser, - messages: data.messages, - allowed: data.allowed, - title: '[[pages:chat, ' + data.toUser.username + ']]', - breadcrumbs: helpers.buildBreadcrumbs([{text: '[[pages:chats]]', url: '/chats'}, {text: data.toUser.username}]) - }); - }); - }); -}; module.exports = accountsController; diff --git a/src/controllers/accounts/chats.js b/src/controllers/accounts/chats.js new file mode 100644 index 0000000000..11f6535d8c --- /dev/null +++ b/src/controllers/accounts/chats.js @@ -0,0 +1,91 @@ +'use strict'; + +var async = require('async'), + nconf = require('nconf'), + + user = require('../../user'), + messaging = require('../../messaging'), + meta = require('../../meta'), + helpers = require('../helpers'), + utils = require('../../../public/src/utils'); + +var chatsController = {}; + +chatsController.get = function(req, res, callback) { + if (parseInt(meta.config.disableChat, 10) === 1) { + return callback(); + } + + // In case a userNAME is passed in instead of a slug, the route should not 404 + var slugified = utils.slugify(req.params.userslug); + if (req.params.userslug && req.params.userslug !== slugified) { + return res.redirect(nconf.get('relative_path') + '/chats/' + slugified); + } + + async.parallel({ + contacts: async.apply(user.getFollowing, req.user.uid, 0, 199), + recentChats: async.apply(messaging.getRecentChats, req.user.uid, 0, 19) + }, function(err, results) { + if (err) { + return callback(err); + } + + if (results.recentChats.users && results.recentChats.users.length) { + var contactUids = results.recentChats.users.map(function(chatObj) { + return parseInt(chatObj.uid, 10); + }); + + results.contacts = results.contacts.filter(function(contact) { + return contactUids.indexOf(parseInt(contact.uid, 10)) === -1; + }); + } + + if (!req.params.userslug) { + return res.render('chats', { + chats: results.recentChats.users, + nextStart: results.recentChats.nextStart, + contacts: results.contacts, + allowed: true, + title: '[[pages:chats]]', + breadcrumbs: helpers.buildBreadcrumbs([{text: '[[pages:chats]]'}]) + }); + } + + async.waterfall([ + async.apply(user.getUidByUserslug, req.params.userslug), + function(toUid, next) { + if (!toUid || parseInt(toUid, 10) === parseInt(req.user.uid, 10)) { + return callback(); + } + + async.parallel({ + toUser: async.apply(user.getUserFields, toUid, ['uid', 'username']), + messages: async.apply(messaging.getMessages, { + fromuid: req.user.uid, + touid: toUid, + since: 'recent', + isNew: false + }), + allowed: async.apply(messaging.canMessage, req.user.uid, toUid) + }, next); + } + ], function(err, data) { + if (err) { + return callback(err); + } + + res.render('chats', { + chats: results.recentChats.users, + nextStart: results.recentChats.nextStart, + contacts: results.contacts, + meta: data.toUser, + messages: data.messages, + allowed: data.allowed, + title: '[[pages:chat, ' + data.toUser.username + ']]', + breadcrumbs: helpers.buildBreadcrumbs([{text: '[[pages:chats]]', url: '/chats'}, {text: data.toUser.username}]) + }); + }); + }); +}; + +module.exports = chatsController; \ No newline at end of file diff --git a/src/controllers/accounts/edit.js b/src/controllers/accounts/edit.js index 66b8f8ff15..1120ad65e3 100644 --- a/src/controllers/accounts/edit.js +++ b/src/controllers/accounts/edit.js @@ -1,7 +1,12 @@ 'use strict'; var async = require('async'), + fs = require('fs'), + nconf = require('nconf'), + winston = require('winston'), + db = require('../../database'), + user = require('../../user'), meta = require('../../meta'), helpers = require('../helpers'), accountHelpers = require('./helpers'); @@ -35,4 +40,46 @@ editController.get = function(req, res, callback) { }); }; + +editController.uploadPicture = function (req, res, next) { + var userPhoto = req.files.files[0]; + + var updateUid = req.uid; + + async.waterfall([ + function(next) { + user.getUidByUserslug(req.params.userslug, next); + }, + function(uid, next) { + if (parseInt(updateUid, 10) === parseInt(uid, 10)) { + return next(); + } + + user.isAdministrator(req.uid, function(err, isAdmin) { + if (err) { + return next(err); + } + + if (!isAdmin) { + return helpers.notAllowed(req, res); + } + updateUid = uid; + next(); + }); + }, + function(next) { + user.uploadPicture(updateUid, userPhoto, next); + } + ], function(err, image) { + fs.unlink(userPhoto.path, function(err) { + winston.error('unable to delete picture ' + userPhoto.path, err); + }); + if (err) { + return next(err); + } + + res.json([{name: userPhoto.name, 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/follow.js b/src/controllers/accounts/follow.js new file mode 100644 index 0000000000..f9dc72c6f3 --- /dev/null +++ b/src/controllers/accounts/follow.js @@ -0,0 +1,48 @@ +'use strict'; + +var async = require('async'), + + user = require('../../user'), + helpers = require('../helpers'), + accountHelpers = require('./helpers'); + +var followController = {}; + +followController.getFollowing = function(req, res, next) { + getFollow('account/following', 'following', req, res, next); +}; + +followController.getFollowers = function(req, res, next) { + getFollow('account/followers', 'followers', req, res, next); +}; + +function getFollow(tpl, name, req, res, callback) { + var userData; + + async.waterfall([ + function(next) { + accountHelpers.getBaseUser(req.params.userslug, req.uid, next); + }, + function(data, next) { + userData = data; + if (!userData) { + return callback(); + } + var method = name === 'following' ? 'getFollowing' : 'getFollowers'; + user[method](userData.uid, 0, 49, next); + } + ], function(err, users) { + if (err) { + return callback(err); + } + + userData.users = users; + userData.nextStart = 50; + userData.title = '[[pages:' + tpl + ', ' + userData.username + ']]'; + userData.breadcrumbs = helpers.buildBreadcrumbs([{text: userData.username, url: '/user/' + userData.userslug}, {text: '[[user:' + name + ']]'}]); + + res.render(tpl, userData); + }); +} + +module.exports = followController; \ No newline at end of file diff --git a/src/controllers/accounts/groups.js b/src/controllers/accounts/groups.js new file mode 100644 index 0000000000..e19034c908 --- /dev/null +++ b/src/controllers/accounts/groups.js @@ -0,0 +1,54 @@ +'use strict'; + + +var async = require('async'), + + groups = require('../../groups'), + helpers = require('../helpers'), + accountHelpers = require('./helpers'); + +var groupsController = {}; + + +groupsController.get = function(req, res, callback) { + var userData; + var groupsData; + async.waterfall([ + function (next) { + accountHelpers.getBaseUser(req.params.userslug, req.uid, next); + }, + function (_userData, next) { + userData = _userData; + if (!userData) { + return callback(); + } + + groups.getUserGroups([userData.uid], next); + }, + function (_groupsData, next) { + groupsData = _groupsData[0]; + var groupNames = groupsData.filter(Boolean).map(function(group) { + return group.name; + }); + + groups.getMemberUsers(groupNames, 0, 3, next); + }, + function (members, next) { + groupsData.forEach(function(group, index) { + group.members = members[index]; + }); + next(); + } + ], function(err) { + if (err) { + return callback(err); + } + + userData.groups = groupsData; + userData.title = '[[pages:account/groups, ' + userData.username + ']]'; + userData.breadcrumbs = helpers.buildBreadcrumbs([{text: userData.username, url: '/user/' + userData.userslug}, {text: '[[global:header.groups]]'}]); + res.render('account/groups', userData); + }); +}; + +module.exports = groupsController; \ No newline at end of file diff --git a/src/controllers/accounts/helpers.js b/src/controllers/accounts/helpers.js index e9706834b2..4646986cd0 100644 --- a/src/controllers/accounts/helpers.js +++ b/src/controllers/accounts/helpers.js @@ -105,4 +105,42 @@ helpers.getUserDataByUserSlug = function(userslug, callerUID, callback) { ], callback); }; + +helpers.getBaseUser = function(userslug, callerUID, callback) { + async.waterfall([ + function (next) { + user.getUidByUserslug(userslug, next); + }, + function (uid, next) { + if (!uid) { + return callback(null, null); + } + + async.parallel({ + user: function(next) { + user.getUserFields(uid, ['uid', 'username', 'userslug'], next); + }, + isAdmin: function(next) { + user.isAdministrator(callerUID, next); + }, + profile_links: function(next) { + plugins.fireHook('filter:user.profileLinks', [], next); + } + }, next); + }, + function (results, next) { + if (!results.user) { + return callback(); + } + + results.user.yourid = callerUID; + results.user.theirid = results.user.uid; + 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; + next(null, results.user); + } + ], callback); +}; + module.exports = helpers; \ No newline at end of file diff --git a/src/controllers/accounts/notifications.js b/src/controllers/accounts/notifications.js new file mode 100644 index 0000000000..2f540e9d94 --- /dev/null +++ b/src/controllers/accounts/notifications.js @@ -0,0 +1,23 @@ +'use strict'; + +var user = require('../../user'), + helpers = require('../helpers'); + + +var notificationsController = {}; + +notificationsController.get = function(req, res, next) { + user.notifications.getAll(req.uid, 40, function(err, notifications) { + if (err) { + return next(err); + } + res.render('notifications', { + notifications: notifications, + title: '[[pages:notifications]]', + breadcrumbs: helpers.buildBreadcrumbs([{text: '[[pages:notifications]]'}]) + }); + }); +}; + + +module.exports = notificationsController; diff --git a/src/controllers/accounts/posts.js b/src/controllers/accounts/posts.js new file mode 100644 index 0000000000..f17bb675ce --- /dev/null +++ b/src/controllers/accounts/posts.js @@ -0,0 +1,84 @@ +'use strict'; + + +var async = require('async'), + + db = require('../../database'), + user = require('../../user'), + posts = require('../../posts'), + topics = require('../../topics'), + pagination = require('../../pagination'), + helpers = require('../helpers'), + accountHelpers = require('./helpers'); + +var postsController = {}; + +postsController.getFavourites = function(req, res, next) { + getFromUserSet('account/favourites', 'favourites', '[[user:favourites]]', posts.getPostSummariesFromSet, 'posts', req, res, next); +}; + +postsController.getPosts = function(req, res, next) { + getFromUserSet('account/posts', 'posts', '[[global:posts]]', posts.getPostSummariesFromSet, 'posts', req, res, next); +}; + +postsController.getWatchedTopics = function(req, res, next) { + getFromUserSet('account/watched', 'followed_tids', '[[user:watched]]',topics.getTopicsFromSet, 'topics', req, res, next); +}; + +postsController.getTopics = function(req, res, next) { + getFromUserSet('account/topics', 'topics', '[[global:topics]]', topics.getTopicsFromSet, 'topics', req, res, next); +}; + +function getFromUserSet(tpl, set, crumb, method, type, req, res, next) { + async.parallel({ + settings: function(next) { + user.getSettings(req.uid, next); + }, + userData: function(next) { + accountHelpers.getBaseUser(req.params.userslug, req.uid, next); + } + }, function(err, results) { + if (err || !results.userData) { + return next(err); + } + + var userData = results.userData; + + var setName = 'uid:' + userData.uid + ':' + set; + + var page = Math.max(1, parseInt(req.query.page, 10) || 1); + var itemsPerPage = (tpl === 'account/topics' || tpl === 'account/watched') ? results.settings.topicsPerPage : results.settings.postsPerPage; + + async.parallel({ + itemCount: function(next) { + if (results.settings.usePagination) { + db.sortedSetCard(setName, next); + } else { + next(null, 0); + } + }, + data: function(next) { + var start = (page - 1) * itemsPerPage; + var stop = start + itemsPerPage - 1; + method(setName, req.uid, start, stop, next); + } + }, function(err, results) { + if (err) { + return next(err); + } + + userData[type] = results.data[type]; + userData.nextStart = results.data.nextStart; + + var pageCount = Math.ceil(results.itemCount / itemsPerPage); + userData.pagination = pagination.create(page, pageCount); + + userData.title = '[[pages:' + tpl + ', ' + userData.username + ']]'; + userData.breadcrumbs = helpers.buildBreadcrumbs([{text: userData.username, url: '/user/' + userData.userslug}, {text: crumb}]); + + res.render(tpl, userData); + }); + }); +} + +module.exports = postsController; \ No newline at end of file diff --git a/src/controllers/accounts/settings.js b/src/controllers/accounts/settings.js new file mode 100644 index 0000000000..451711b166 --- /dev/null +++ b/src/controllers/accounts/settings.js @@ -0,0 +1,107 @@ +'use strict'; + +var async = require('async'), + + user = require('../../user'), + groups = require('../../groups'), + languages = require('../../languages'), + meta = require('../../meta'), + plugins = require('../../plugins'), + helpers = require('../helpers'), + accountHelpers = require('./helpers'); + + +var settingsController = {}; + + +settingsController.get = function(req, res, callback) { + var userData; + async.waterfall([ + function(next) { + accountHelpers.getBaseUser(req.params.userslug, req.uid, next); + }, + function(_userData, next) { + userData = _userData; + if (!userData) { + return callback(); + } + async.parallel({ + settings: function(next) { + user.getSettings(userData.uid, next); + }, + userGroups: function(next) { + groups.getUserGroups([userData.uid], next); + }, + languages: function(next) { + languages.list(next); + } + }, next); + }, + function(results, next) { + userData.settings = results.settings; + userData.languages = results.languages; + userData.userGroups = results.userGroups[0]; + plugins.fireHook('filter:user.customSettings', {settings: results.settings, customSettings: [], uid: req.uid}, next); + }, + function(data, next) { + userData.customSettings = data.customSettings; + userData.disableEmailSubscriptions = parseInt(meta.config.disableEmailSubscriptions, 10) === 1; + next(); + } + ], function(err) { + if (err) { + return callback(err); + } + + userData.dailyDigestFreqOptions = [ + {value: 'off', name: '[[user:digest_off]]', selected: 'off' === userData.settings.dailyDigestFreq}, + {value: 'day', name: '[[user:digest_daily]]', selected: 'day' === userData.settings.dailyDigestFreq}, + {value: 'week', name: '[[user:digest_weekly]]', selected: 'week' === userData.settings.dailyDigestFreq}, + {value: 'month', name: '[[user:digest_monthly]]', selected: 'month' === userData.settings.dailyDigestFreq} + ]; + + + userData.bootswatchSkinOptions = [ + { "name": "Default", "value": "default" }, + { "name": "Cerulean", "value": "cerulean" }, + { "name": "Cosmo", "value": "cosmo" }, + { "name": "Cyborg", "value": "cyborg" }, + { "name": "Darkly", "value": "darkly" }, + { "name": "Flatly", "value": "flatly" }, + { "name": "Journal", "value": "journal" }, + { "name": "Lumen", "value": "lumen" }, + { "name": "Paper", "value": "paper" }, + { "name": "Readable", "value": "readable" }, + { "name": "Sandstone", "value": "sandstone" }, + { "name": "Simplex", "value": "simplex" }, + { "name": "Slate", "value": "slate" }, + { "name": "Spacelab", "value": "spacelab" }, + { "name": "Superhero", "value": "superhero" }, + { "name": "United", "value": "united" }, + { "name": "Yeti", "value": "yeti" } + ]; + + userData.bootswatchSkinOptions.forEach(function(skin) { + skin.selected = skin.value === userData.settings.bootswatchSkin; + }); + + userData.userGroups.forEach(function(group) { + group.selected = group.name === userData.settings.groupTitle; + }); + + userData.languages.forEach(function(language) { + language.selected = language.code === userData.settings.userLang; + }); + + userData.disableCustomUserSkins = parseInt(meta.config.disableCustomUserSkins, 10) === 1; + + userData.title = '[[pages:account/settings]]'; + userData.breadcrumbs = helpers.buildBreadcrumbs([{text: userData.username, url: '/user/' + userData.userslug}, {text: '[[user:settings]]'}]); + + res.render('account/settings', userData); + }); +}; + + + +module.exports = settingsController; \ No newline at end of file diff --git a/src/controllers/api.js b/src/controllers/api.js index 14dbe4b309..1e5369fb59 100644 --- a/src/controllers/api.js +++ b/src/controllers/api.js @@ -174,4 +174,40 @@ apiController.getObject = function(req, res, next) { }; +apiController.getUserByUID = function(req, res, next) { + var uid = req.params.uid ? req.params.uid : 0; + + async.parallel({ + userData: async.apply(user.getUserData, uid), + settings: async.apply(user.getSettings, uid) + }, function(err, results) { + if (err || !results.userData) { + return next(err); + } + + results.userData.email = results.settings.showemail ? results.userData.email : undefined; + results.userData.fullname = results.settings.showfullname ? results.userData.fullname : undefined; + + res.json(results.userData); + }); +}; + + +apiController.getModerators = function(req, res, next) { + categories.getModerators(req.params.cid, function(err, moderators) { + res.json({moderators: moderators}); + }); +}; + + +apiController.getRecentPosts = function(req, res, next) { + posts.getRecentPosts(req.uid, 0, 19, req.params.term, function (err, data) { + if (err) { + return next(err); + } + + res.json(data); + }); +}; + module.exports = apiController; diff --git a/src/routes/accounts.js b/src/routes/accounts.js index ecf2e1be99..40163e095c 100644 --- a/src/routes/accounts.js +++ b/src/routes/accounts.js @@ -8,17 +8,17 @@ module.exports = function (app, middleware, controllers) { var accountMiddlewares = [middleware.checkGlobalPrivacySettings, middleware.checkAccountPermissions]; setupPageRoute(app, '/user/:userslug', middleware, middlewares, controllers.accounts.profile.get); - setupPageRoute(app, '/user/:userslug/following', middleware, middlewares, controllers.accounts.getFollowing); - setupPageRoute(app, '/user/:userslug/followers', middleware, middlewares, controllers.accounts.getFollowers); - setupPageRoute(app, '/user/:userslug/posts', middleware, middlewares, controllers.accounts.getPosts); - setupPageRoute(app, '/user/:userslug/topics', middleware, middlewares, controllers.accounts.getTopics); - setupPageRoute(app, '/user/:userslug/groups', middleware, middlewares, controllers.accounts.getGroups); + setupPageRoute(app, '/user/:userslug/following', middleware, middlewares, controllers.accounts.follow.getFollowing); + setupPageRoute(app, '/user/:userslug/followers', middleware, middlewares, controllers.accounts.follow.getFollowers); + setupPageRoute(app, '/user/:userslug/posts', middleware, middlewares, controllers.accounts.posts.getPosts); + setupPageRoute(app, '/user/:userslug/topics', middleware, middlewares, controllers.accounts.posts.getTopics); + setupPageRoute(app, '/user/:userslug/groups', middleware, middlewares, controllers.accounts.groups.get); - setupPageRoute(app, '/user/:userslug/favourites', middleware, accountMiddlewares, controllers.accounts.getFavourites); - setupPageRoute(app, '/user/:userslug/watched', middleware, accountMiddlewares, controllers.accounts.getWatchedTopics); + setupPageRoute(app, '/user/:userslug/favourites', middleware, accountMiddlewares, controllers.accounts.posts.getFavourites); + setupPageRoute(app, '/user/:userslug/watched', middleware, accountMiddlewares, controllers.accounts.posts.getWatchedTopics); setupPageRoute(app, '/user/:userslug/edit', middleware, accountMiddlewares, controllers.accounts.edit.get); - setupPageRoute(app, '/user/:userslug/settings', middleware, accountMiddlewares, controllers.accounts.accountSettings); + setupPageRoute(app, '/user/:userslug/settings', middleware, accountMiddlewares, controllers.accounts.settings.get); - setupPageRoute(app, '/notifications', middleware, [middleware.authenticate], controllers.accounts.getNotifications); - setupPageRoute(app, '/chats/:userslug?', middleware, [middleware.redirectToLoginIfGuest], controllers.accounts.getChats); + setupPageRoute(app, '/notifications', middleware, [middleware.authenticate], controllers.accounts.notifications.get); + setupPageRoute(app, '/chats/:userslug?', middleware, [middleware.redirectToLoginIfGuest], controllers.accounts.chats.get); }; diff --git a/src/routes/api.js b/src/routes/api.js index 7528c7b917..e0f1684f05 100644 --- a/src/routes/api.js +++ b/src/routes/api.js @@ -14,13 +14,13 @@ module.exports = function(app, middleware, controllers) { router.get('/config', middleware.applyCSRF, controllers.api.getConfig); router.get('/widgets/render', controllers.api.renderWidgets); - router.get('/user/uid/:uid', middleware.checkGlobalPrivacySettings, controllers.accounts.getUserByUID); + router.get('/user/uid/:uid', middleware.checkGlobalPrivacySettings, controllers.api.getUserByUID); router.get('/:type/pid/:id', controllers.api.getObject); router.get('/:type/tid/:id', controllers.api.getObject); router.get('/:type/cid/:id', controllers.api.getObject); - router.get('/categories/:cid/moderators', getModerators); - router.get('/recent/posts/:term?', getRecentPosts); + router.get('/categories/:cid/moderators', controllers.api.getModerators); + router.get('/recent/posts/:term?', controllers.api.getRecentPosts); router.get('/unread/total', middleware.authenticate, controllers.unread.unreadTotal); var multipart = require('connect-multiparty'); @@ -28,22 +28,6 @@ module.exports = function(app, middleware, controllers) { var middlewares = [multipartMiddleware, middleware.validateFiles, middleware.applyCSRF]; 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.uploadPicture); + router.post('/user/:userslug/uploadpicture', middlewares.concat([middleware.authenticate, middleware.checkGlobalPrivacySettings, middleware.checkAccountPermissions]), controllers.accounts.edit.uploadPicture); }; -function getModerators(req, res, next) { - categories.getModerators(req.params.cid, function(err, moderators) { - res.json({moderators: moderators}); - }); -} - - -function getRecentPosts(req, res, next) { - posts.getRecentPosts(req.uid, 0, 19, req.params.term, function (err, data) { - if (err) { - return next(err); - } - - res.json(data); - }); -} \ No newline at end of file