diff --git a/public/language/en-GB/admin/settings/group.json b/public/language/en-GB/admin/settings/group.json index 1ae88c9cf5..fe3e39915b 100644 --- a/public/language/en-GB/admin/settings/group.json +++ b/public/language/en-GB/admin/settings/group.json @@ -5,6 +5,7 @@ "private-groups.warning": "Beware! If this option is disabled and you have private groups, they automatically become public.", "allow-creation": "Allow Group Creation", "allow-creation-help": "If enabled, users can create groups (Default: disabled)", + "allow-multiple-badges-help": "This flag can be used to allow users to select multiple group badges, requires theme support.", "max-name-length": "Maximum Group Name Length", "cover-image": "Group Cover Image", "default-cover": "Default Cover Images", diff --git a/public/src/client/account/edit.js b/public/src/client/account/edit.js index 8b270a8fd2..9956c659c6 100644 --- a/public/src/client/account/edit.js +++ b/public/src/client/account/edit.js @@ -37,6 +37,8 @@ define('forum/account/edit', ['forum/account/header', 'translator', 'components' aboutme: $('#inputAboutMe').val(), }; + userData.groupTitle = JSON.stringify(Array.isArray(userData.groupTitle) ? userData.groupTitle : [userData.groupTitle]); + $(window).trigger('action:profile.update', userData); socket.emit('user.updateProfile', userData, function (err, data) { diff --git a/src/controllers/accounts/edit.js b/src/controllers/accounts/edit.js index 3402c3052a..af92cdc7bc 100644 --- a/src/controllers/accounts/edit.js +++ b/src/controllers/accounts/edit.js @@ -35,6 +35,7 @@ editController.get = function (req, res, callback) { userData.maximumAboutMeLength = parseInt(meta.config.maximumAboutMeLength, 10) || 1000; userData.maximumProfileImageSize = parseInt(meta.config.maximumProfileImageSize, 10); userData.allowProfileImageUploads = parseInt(meta.config.allowProfileImageUploads, 10) === 1; + userData.allowMultipleBadges = parseInt(meta.config.allowMultipleBadges, 10) === 1; userData.allowAccountDelete = parseInt(meta.config.allowAccountDelete, 10) === 1; userData.allowWebsite = !userData.isSelf || parseInt(userData.reputation, 10) >= (parseInt(meta.config['min:rep:website'], 10) || 0); userData.allowAboutMe = !userData.isSelf || parseInt(userData.reputation, 10) >= (parseInt(meta.config['min:rep:aboutme'], 10) || 0); @@ -45,8 +46,12 @@ editController.get = function (req, res, callback) { userData.groups = userData.groups.filter(function (group) { return group && group.userTitleEnabled && !groups.isPrivilegeGroup(group.name) && group.name !== 'registered-users'; }); + + if (!userData.allowMultipleBadges) { + userData.groupTitle = userData.groupTitleArray[0]; + } userData.groups.forEach(function (group) { - group.selected = group.name === userData.groupTitle; + group.selected = userData.groupTitleArray.includes(group.name); }); userData.title = '[[pages:account/edit, ' + userData.username + ']]'; diff --git a/src/controllers/topics.js b/src/controllers/topics.js index 9e89a1e929..40299ceb9b 100644 --- a/src/controllers/topics.js +++ b/src/controllers/topics.js @@ -145,6 +145,7 @@ topicsController.get = function (req, res, callback) { topicData.postEditDuration = parseInt(meta.config.postEditDuration, 10) || 0; topicData.postDeleteDuration = parseInt(meta.config.postDeleteDuration, 10) || 0; topicData.scrollToMyPost = settings.scrollToMyPost; + topicData.allowMultipleBadges = parseInt(meta.config.allowMultipleBadges, 10) === 1; topicData.rssFeedUrl = nconf.get('relative_path') + '/topic/' + topicData.tid + '.rss'; if (req.loggedIn) { topicData.rssFeedUrl += '?uid=' + req.uid + '&token=' + rssToken; diff --git a/src/posts/user.js b/src/posts/user.js index 8fd1e08bb0..e0df76c2a3 100644 --- a/src/posts/user.js +++ b/src/posts/user.js @@ -2,6 +2,7 @@ var async = require('async'); var validator = require('validator'); +var _ = require('lodash'); var user = require('../user'); var groups = require('../groups'); @@ -15,11 +16,16 @@ module.exports = function (Posts) { var userData; var userSettings; var canUseSignature; + var allowMultipleBadges = parseInt(meta.config.allowMultipleBadges, 10) === 1; async.waterfall([ function (next) { async.parallel({ userData: function (next) { - user.getUsersFields(uids, ['uid', 'username', 'fullname', 'userslug', 'reputation', 'postcount', 'picture', 'signature', 'banned', 'status', 'lastonline', 'groupTitle'], next); + user.getUsersFields(uids, [ + 'uid', 'username', 'fullname', 'userslug', + 'reputation', 'postcount', 'picture', 'signature', + 'banned', 'status', 'lastonline', 'groupTitle', + ], next); }, userSettings: function (next) { user.getMultipleUserSettings(uids, next); @@ -34,10 +40,10 @@ module.exports = function (Posts) { userSettings = results.userSettings; canUseSignature = results.canUseSignature; var groupTitles = userData.map(function (userData) { - return userData && userData.groupTitle; - }).filter(function (groupTitle, index, array) { - return groupTitle && array.indexOf(groupTitle) === index; + return userData && userData.groupTitleArray; }); + groupTitles = _.uniq(_.flatten(groupTitles)); + groups.getGroupsData(groupTitles, next); }, function (groupsData, next) { @@ -64,6 +70,8 @@ module.exports = function (Posts) { userData.status = user.getStatus(userData); userData.signature = validator.escape(String(userData.signature || '')); userData.fullname = userSettings[index].showfullname ? validator.escape(String(userData.fullname || '')) : undefined; + userData.selectedGroups = []; + if (parseInt(meta.config.hideFullname, 10) === 1) { userData.fullname = undefined; } @@ -73,11 +81,11 @@ module.exports = function (Posts) { async.waterfall([ function (next) { async.parallel({ - isMemberOfGroup: function (next) { - if (!userData.groupTitle || !groupsMap[userData.groupTitle]) { + isMemberOfGroups: function (next) { + if (!Array.isArray(userData.groupTitleArray) || !userData.groupTitleArray.length) { return next(); } - groups.isMember(userData.uid, userData.groupTitle, next); + groups.isMemberOfGroups(userData.uid, userData.groupTitleArray, next); }, signature: function (next) { if (!userData.signature || !canUseSignature || parseInt(meta.config.disableSignatures, 10) === 1) { @@ -92,8 +100,12 @@ module.exports = function (Posts) { }, next); }, function (results, next) { - if (results.isMemberOfGroup && userData.groupTitle && groupsMap[userData.groupTitle]) { - userData.selectedGroup = groupsMap[userData.groupTitle]; + if (results.isMemberOfGroups && userData.groupTitleArray) { + userData.groupTitleArray.forEach(function (userGroup, index) { + if (results.isMemberOfGroups[index] && groupsMap[userGroup]) { + userData.selectedGroups.push(groupsMap[userGroup]); + } + }); } userData.custom_profile_info = results.customProfileInfo.profile; diff --git a/src/user/data.js b/src/user/data.js index db41509aa0..bec2f2a216 100644 --- a/src/user/data.js +++ b/src/user/data.js @@ -135,7 +135,9 @@ module.exports = function (User) { if (!user) { return; } - + if (user.hasOwnProperty('groupTitle')) { + parseGroupTitle(user); + } if (user.hasOwnProperty('username')) { user.username = validator.escape(user.username ? user.username.toString() : ''); } @@ -192,6 +194,20 @@ module.exports = function (User) { plugins.fireHook('filter:users.get', users, callback); } + function parseGroupTitle(user) { + try { + user.groupTitleArray = JSON.parse(user.groupTitle); + } catch (err) { + user.groupTitleArray = [user.groupTitle]; + } + if (!Array.isArray(user.groupTitleArray)) { + user.groupTitleArray = [user.groupTitleArray]; + } + if (parseInt(meta.config.allowMultipleBadges, 10) !== 1) { + user.groupTitleArray = [user.groupTitleArray[0]]; + } + } + User.getDefaultAvatar = function () { if (!meta.config.defaultAvatar) { return ''; diff --git a/src/views/admin/settings/group.tpl b/src/views/admin/settings/group.tpl index fd696cb5ad..6f267baf57 100644 --- a/src/views/admin/settings/group.tpl +++ b/src/views/admin/settings/group.tpl @@ -29,6 +29,17 @@ [[admin/settings/group:allow-creation-help]]

+
+ +
+ +

+ [[admin/settings/group:allow-multiple-badges-help]] +

+