diff --git a/package.json b/package.json index d1a4724a42..fb117469dd 100644 --- a/package.json +++ b/package.json @@ -61,7 +61,7 @@ "nodebb-plugin-spam-be-gone": "0.4.10", "nodebb-rewards-essentials": "0.0.9", "nodebb-theme-lavender": "3.0.14", - "nodebb-theme-persona": "4.1.49", + "nodebb-theme-persona": "4.1.50", "nodebb-theme-vanilla": "5.1.33", "nodebb-widget-essentials": "2.0.11", "nodemailer": "2.0.0", diff --git a/public/language/en_GB/groups.json b/public/language/en_GB/groups.json index 8d129fe376..2efc9a69fc 100644 --- a/public/language/en_GB/groups.json +++ b/public/language/en_GB/groups.json @@ -59,5 +59,7 @@ "membership.reject": "Reject", "new-group.group_name": "Group Name:", - "upload-group-cover": "Upload group cover" + "upload-group-cover": "Upload group cover", + "bulk-invite-instructions": "Enter a list of comma separated usernames to invite to this group", + "bulk-invite": "Bulk Invite" } \ No newline at end of file diff --git a/public/src/client/groups/details.js b/public/src/client/groups/details.js index f71b37886e..d2f1cfbd8d 100644 --- a/public/src/client/groups/details.js +++ b/public/src/client/groups/details.js @@ -1,5 +1,5 @@ "use strict"; -/* globals define, socket, ajaxify, app, bootbox, utils, RELATIVE_PATH */ +/* globals define, socket, ajaxify, app, bootbox, utils, config */ define('forum/groups/details', [ 'forum/groups/memberlist', @@ -227,23 +227,41 @@ define('forum/groups/details', [ }; function handleMemberInvitations() { - if (ajaxify.data.group.isOwner) { - var searchInput = $('[component="groups/members/invite"]'); - require(['autocomplete'], function(autocomplete) { - autocomplete.user(searchInput, function(event, selected) { - socket.emit('groups.issueInvite', { - toUid: selected.item.user.uid, - groupName: ajaxify.data.group.name - }, function(err) { - if (!err) { - ajaxify.refresh(); - } else { - app.alertError(err.message); - } - }); + if (!ajaxify.data.group.isOwner) { + return; + } + + var searchInput = $('[component="groups/members/invite"]'); + require(['autocomplete'], function(autocomplete) { + autocomplete.user(searchInput, function(event, selected) { + socket.emit('groups.issueInvite', { + toUid: selected.item.user.uid, + groupName: ajaxify.data.group.name + }, function(err) { + if (err) { + return app.alertError(err.message); + } + ajaxify.refresh(); }); }); - } + }); + + $('[component="groups/members/bulk-invite-button"]').on('click', function() { + var usernames = $('[component="groups/members/bulk-invite"]').val(); + if (!usernames) { + return false; + } + socket.emit('groups.issueMassInvite', { + usernames: usernames, + groupName: ajaxify.data.group.name + }, function(err) { + if (err) { + return app.alertError(err.message); + } + ajaxify.refresh(); + }); + return false; + }); } function removeCover() { diff --git a/src/socket.io/groups.js b/src/socket.io/groups.js index 5df97f80f5..41de928b51 100644 --- a/src/socket.io/groups.js +++ b/src/socket.io/groups.js @@ -135,6 +135,28 @@ SocketGroups.issueInvite = isOwner(function(socket, data, callback) { groups.invite(data.groupName, data.toUid, callback); }); +SocketGroups.issueMassInvite = isOwner(function(socket, data, callback) { + if (!data || !data.usernames || !data.groupName) { + return callback(new Error('[[error:invalid-data]]')); + } + var usernames = data.usernames.split(','); + usernames = usernames.map(function(username) { + return username && username.trim(); + }); + user.getUidsByUsernames(usernames, function(err, uids) { + if (err) { + return callback(err); + } + uids = uids.filter(function(uid) { + return !!uid && parseInt(uid, 10); + }); + + async.eachSeries(uids, function(uid, next) { + groups.invite(data.groupName, uid, callback); + }, callback); + }); +}); + SocketGroups.rescindInvite = isOwner(function(socket, data, callback) { groups.rejectMembership(data.groupName, data.toUid, callback); });