From 291b5eb1e70f31dae15c5c2f7bedcff563b72bd2 Mon Sep 17 00:00:00 2001 From: Matteo Pagliazzi Date: Thu, 5 Feb 2015 17:56:31 +0100 Subject: [PATCH 1/7] partial --- src/controllers/groups.js | 193 ++++++++++++++++++++++++++------------ src/controllers/user.js | 40 -------- src/routes/apiv2.coffee | 11 +-- 3 files changed, 132 insertions(+), 112 deletions(-) diff --git a/src/controllers/groups.js b/src/controllers/groups.js index 7d874e0d50..1acad39fdb 100644 --- a/src/controllers/groups.js +++ b/src/controllers/groups.js @@ -508,80 +508,149 @@ api.leave = function(req, res, next) { }) } -api.invite = function(req, res, next) { - var group = res.locals.group; - var uuid = req.query.uuid; +var inviteByUUID = function(uuids, group, req, res, next){ + uuids = Array.isArray(uuids) ? uuids : [uuids]; - User.findById(uuid, function(err,invite){ - if (err) return next(err); - if (!invite) - return res.json(400,{err:'User with id "' + uuid + '" not found'}); - if (group.type == 'guild') { - if (_.contains(group.members,uuid)) - return res.json(400,{err: "User already in that group"}); - if (invite.invitations && invite.invitations.guilds && _.find(invite.invitations.guilds, {id:group._id})) - return res.json(400, {err:"User already invited to that group"}); - sendInvite(); - } else if (group.type == 'party') { - if (invite.invitations && !_.isEmpty(invite.invitations.party)) - return res.json(400,{err:"User already pending invitation."}); - Group.find({type:'party', members:{$in:[uuid]}}, function(err, groups){ - if (err) return next(err); - if (!_.isEmpty(groups)) - return res.json(400,{err:"User already in a party."}) + async.each(uuids, function(uuid, cb){ + User.findById(uuid, function(err,invite){ + if (err) return cb(err); + if (!invite) + return cb({code:400,err:'User with id "' + uuid + '" not found'}); + if (group.type == 'guild') { + if (_.contains(group.members,uuid)) + return cb({code:400,err: "User already in that group"}); + if (invite.invitations && invite.invitations.guilds && _.find(invite.invitations.guilds, {id:group._id})) + return cb({code:400,err:"User already invited to that group"}); sendInvite(); - }); - } - - function sendInvite (){ - if(group.type === 'guild'){ - invite.invitations.guilds.push({id: group._id, name: group.name, inviter:res.locals.user._id}); - }else{ - //req.body.type in 'guild', 'party' - invite.invitations.party = {id: group._id, name: group.name, inviter:res.locals.user._id}; + } else if (group.type == 'party') { + if (invite.invitations && !_.isEmpty(invite.invitations.party)) + return cb({code:400,err:"User already pending invitation."}); + Group.find({type:'party', members:{$in:[uuid]}}, function(err, groups){ + if (err) return cb(err); + if (!_.isEmpty(groups)) + return cb({code:400,err:"User already in a party."}) + sendInvite(); + }); } - group.invites.push(invite._id); - - async.series([ - function(cb){ - invite.save(cb); - }, - function(cb){ - group.save(cb); - }, - function(cb){ - populateQuery(group.type, Group.findById(group._id)).exec(cb); + function sendInvite (){ + if(group.type === 'guild'){ + invite.invitations.guilds.push({id: group._id, name: group.name, inviter:res.locals.user._id}); + }else{ + //req.body.type in 'guild', 'party' + invite.invitations.party = {id: group._id, name: group.name, inviter:res.locals.user._id}; } - ], function(err, results){ - if (err) return next(err); - if(invite.preferences.emailNotifications['invited' + (group.type == 'guild' ? 'Guild' : 'Party')] !== false){ - var emailVars = [ - {name: 'INVITER', content: utils.getUserInfo(res.locals.user, ['name']).name} - ]; + group.invites.push(invite._id); - if(group.type == 'guild'){ - emailVars.push( - {name: 'GUILD_NAME', content: group.name}, - {name: 'GUILD_URL', content: nconf.get('BASE_URL') + '/#/options/groups/guilds/public'} - ); - }else{ - emailVars.push( - {name: 'PARTY_NAME', content: group.name}, - {name: 'PARTY_URL', content: nconf.get('BASE_URL') + '/#/options/groups/party'} - ) + async.series([ + function(cb){ + invite.save(cb); + }, + function(cb){ + group.save(cb); + } + ], function(err, results){ + if (err) return cb(err); + + if(invite.preferences.emailNotifications['invited' + (group.type == 'guild' ? 'Guild' : 'Party')] !== false){ + var emailVars = [ + {name: 'INVITER', content: utils.getUserInfo(res.locals.user, ['name']).name} + ]; + + if(group.type == 'guild'){ + emailVars.push( + {name: 'GUILD_NAME', content: group.name}, + {name: 'GUILD_URL', content: nconf.get('BASE_URL') + '/#/options/groups/guilds/public'} + ); + }else{ + emailVars.push( + {name: 'PARTY_NAME', content: group.name}, + {name: 'PARTY_URL', content: nconf.get('BASE_URL') + '/#/options/groups/party'} + ) + } + + utils.txnEmail(invite, ('invited-' + (group.type == 'guild' ? 'guild' : 'party')), emailVars); } - utils.txnEmail(invite, ('invited-' + (group.type == 'guild' ? 'guild' : 'party')), emailVars); - } + cb(); + }); + } + }); + }, function(err){ + if(err){ + return err.code ? res.json(err.code, {err: err.err}) : next(err); + } - // Have to return whole group and its members for angular to show the invited user - res.json(results[2]); - group = uuid = null; - }); + populateQuery(group.type, Group.findById(group._id)).exec(function(err, populatedGroup){ + if(err) return next(err); + + res.json(populatedGroup); + }); + }); + +}; + +var inviteByEmail = function(invites, group, req, res, next){ + var usersAlreadyRegistered = []; + + async.each(invites, function(invite, cb){ + if (invite.email) { + User.findOne({$or: [ + {'auth.local.email': invite.email}, + {'auth.facebook.emails.value': invite.email} + ]}).select({_id: true, 'preferences.emailNotifications': true}) + .exec(function(err, userToContact){ + if(err) return next(err); + + if(userToContact){ + usersAlreadyRegistered.push(userToContact._id); + return cb(); + } + + var link = nconf.get('BASE_URL')+'?groupInvite='+ utils.encrypt(JSON.stringify({id:group._id, inviter:res.locals.user._id, name:group.name})); + + var variables = [ + {name: 'LINK', content: link}, + {name: 'INVITER', content: req.body.inviter || utils.getUserInfo(res.locals.user, ['name']).name} + ]; + + // We check for unsubscribeFromAll here because don't pass through utils.getUserInfo + if(!userToContact || + (invite.preferences.emailNotifications['invited' + (group.type == 'guild' ? 'Guild' : 'Party')] !== false && + userToContact.preferences.emailNotifications.unsubscribeFromAll !== true)){ + // TODO implement "users can only be invited once" + invite.canSend = true; + utils.txnEmail(invite, 'invite-friend', variables); + } + + cb(); + }); + }else{ + cb('Email address is required.'); + } + }, function(err){ + if(err) return next(err); + + if(usersAlreadyRegistered.length > 0){ + inviteByUUID(usersAlreadyRegistered, group, req, res, next); + }else{ + res.send(200); } }); +}; + +api.invite = function(req, res, next){ + var group = res.locals.group; + var invitationType = req.query.invitationType; + + if(invitationType == 'uuid'){ + inviteByUUID(req.query.uuid, group, req, res, next); + }else if(invitationType == 'email'){ + inviteByEmail(req.body.emails, group, req, res, next) + }else{ + return res.json(400,{err: "Can invite only by email or uuid"}); + } } api.removeMember = function(req, res, next){ diff --git a/src/controllers/user.js b/src/controllers/user.js index ae2987fb8c..09c27ddd89 100644 --- a/src/controllers/user.js +++ b/src/controllers/user.js @@ -409,46 +409,6 @@ api.cast = function(req, res, next) { } } -/** - * POST /user/invite-friends - */ -api.inviteFriends = function(req, res, next) { - Group.findOne({type:'party', members:{'$in': [res.locals.user._id]}}).select('_id name').exec(function(err,party){ - if (err) return next(err); - - _.each(req.body.emails, function(invite){ - if (invite.email) { - - User.findOne({$or: [ - {'auth.local.email': invite.email}, - {'auth.facebook.emails.value': invite.email} - ]}).select({_id: true, 'preferences.emailNotifications': true}) - .exec(function(err, userToContact){ - if(err) return next(err); - - var link = nconf.get('BASE_URL')+'?partyInvite='+ utils.encrypt(JSON.stringify({id:party._id, inviter:res.locals.user._id, name:party.name})); - - var variables = [ - {name: 'LINK', content: link}, - {name: 'INVITER', content: req.body.inviter || utils.getUserInfo(res.locals.user, ['name']).name} - ]; - - invite.canSend = true; - - // We check for unsubscribeFromAll here because don't pass through utils.getUserInfo - if(!userToContact || (userToContact.preferences.emailNotifications.invitedParty !== false && - userToContact.preferences.emailNotifications.unsubscribeFromAll !== true)){ - // TODO implement "users can only be invited once" - utils.txnEmail(invite, 'invite-friend', variables); - } - }); - - } - }); - res.send(200); - }) -} - api.sessionPartyInvite = function(req,res,next){ if (!req.session.partyInvite) return next(); var inv = res.locals.user.invitations; diff --git a/src/routes/apiv2.coffee b/src/routes/apiv2.coffee index 39d4523a75..2c8703734b 100644 --- a/src/routes/apiv2.coffee +++ b/src/routes/apiv2.coffee @@ -365,15 +365,6 @@ module.exports = (swagger, v2) -> ] action: user.deleteTag - "/user/social/invite-friends": - spec: - method: 'POST' - description: 'Invite friends via email' - parameters: [ - body 'invites','Array of [{name:"Friend\'s Name", email:"friends@email.com"}] to invite to play in your party','object' - ] - action: user.inviteFriends - # Webhooks "/user/webhooks": spec: @@ -469,7 +460,7 @@ module.exports = (swagger, v2) -> description: "Invite a user to a group" parameters: [ path 'gid','Group id','string' - query 'uuid','User id to invite','string' + query 'invitationType','The type of invitation to send (uuid or email)','string' ] middleware: [auth.auth, i18n.getUserLanguage, groups.attachGroup] action:groups.invite From b069529fe8797bcaf278c6dd3471e3300830cb81 Mon Sep 17 00:00:00 2001 From: Matteo Pagliazzi Date: Mon, 9 Feb 2015 20:16:00 +0100 Subject: [PATCH 2/7] add todos --- src/controllers/groups.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/controllers/groups.js b/src/controllers/groups.js index 1acad39fdb..24472b5b30 100644 --- a/src/controllers/groups.js +++ b/src/controllers/groups.js @@ -573,15 +573,15 @@ var inviteByUUID = function(uuids, group, req, res, next){ utils.txnEmail(invite, ('invited-' + (group.type == 'guild' ? 'guild' : 'party')), emailVars); } + // TODO what does this cb calls? anything? cb(); }); } }); }, function(err){ - if(err){ - return err.code ? res.json(err.code, {err: err.err}) : next(err); - } + if(err) return err.code ? res.json(err.code, {err: err.err}) : next(err); + // TODO pass group from save above don't find it again, or you have to find it again in order to run populate? populateQuery(group.type, Group.findById(group._id)).exec(function(err, populatedGroup){ if(err) return next(err); @@ -616,6 +616,7 @@ var inviteByEmail = function(invites, group, req, res, next){ ]; // We check for unsubscribeFromAll here because don't pass through utils.getUserInfo + // Todo now this should be only for non registered users so no need to check preferences if(!userToContact || (invite.preferences.emailNotifications['invited' + (group.type == 'guild' ? 'Guild' : 'Party')] !== false && userToContact.preferences.emailNotifications.unsubscribeFromAll !== true)){ @@ -635,6 +636,7 @@ var inviteByEmail = function(invites, group, req, res, next){ if(usersAlreadyRegistered.length > 0){ inviteByUUID(usersAlreadyRegistered, group, req, res, next); }else{ + // todo send back group here as we do when inviting by uuid? res.send(200); } }); From fdf0c1d3ec7d145503c7f570ff6d358c1edc55ca Mon Sep 17 00:00:00 2001 From: Matteo Pagliazzi Date: Mon, 9 Feb 2015 20:35:41 +0100 Subject: [PATCH 3/7] bring client side changes and cleanup --- public/js/controllers/groupsCtrl.js | 45 +++++++++++++++---------- public/js/controllers/rootCtrl.js | 1 + views/options/social/group.jade | 10 +----- views/shared/modals/invite-friends.jade | 6 ++-- 4 files changed, 33 insertions(+), 29 deletions(-) diff --git a/public/js/controllers/groupsCtrl.js b/public/js/controllers/groupsCtrl.js index c911b1e2f2..1b4fb9b42c 100644 --- a/public/js/controllers/groupsCtrl.js +++ b/public/js/controllers/groupsCtrl.js @@ -65,15 +65,12 @@ habitrpg.controller("GroupsCtrl", ['$scope', '$rootScope', 'Shared', 'Groups', ' } } - // ------ Invites ------ - - $scope.invite = function(group){ - Groups.Group.invite({gid: group._id, uuid: group.invitee}, undefined, function(){ - group.invitee = ''; - }, function(){ - group.invitee = ''; - }); - } + $scope.openInviteModal = function(group){ + $rootScope.openModal('invite-friends', {controller:'InviteToGroupCtrl', resolve: + {injectedGroup: function(){ + return group; + }}}); + }; //var serializeQs = function(obj, prefix){ // var str = []; @@ -91,14 +88,6 @@ habitrpg.controller("GroupsCtrl", ['$scope', '$rootScope', 'Shared', 'Groups', ' //$scope.inviteLink = function(obj){ // return window.env.BASE_URL + '?' + serializeQs({partyInvite: obj}); //} - $scope.emails = [{name:"",email:""},{name:"",email:""}]; - $scope.inviter = User.user.profile.name; - $scope.inviteEmails = function(inviter, emails){ - $http.post('/api/v2/user/social/invite-friends', {inviter:inviter, emails:emails}).success(function(){ - Notification.text("Invitations sent!"); - $scope.emails = [{name:'',email:''},{name:'',email:''}]; - }); - } $scope.quickReply = function(uid) { Members.selectMember(uid, function(){ @@ -108,6 +97,28 @@ habitrpg.controller("GroupsCtrl", ['$scope', '$rootScope', 'Shared', 'Groups', ' } ]) + .controller('InviteToGroupCtrl', ['$scope', 'User', 'Groups', 'injectedGroup', '$http', function($scope, User, Groups, injectedGroup, $http){ $scope.group = injectedGroup; + + $scope.inviter = User.user.profile.name; + $scope.emails = [{name:"",email:""},{name:"",email:""}]; + + // todo use Groups.Group.invite for everything not raw $http + $scope.inviteEmails = function(){ + $http.post('/api/v2/user/social/invite-friends/' + $scope.group._id, {inviter:$scope.inviter, emails:$scope.emails}).success(function(){ + Notification.text("Invitations sent!"); + $scope.emails = [{name:'',email:''},{name:'',email:''}]; + }); + }; + + $scope.invite = function(){ + Groups.Group.invite({gid: $scope.group._id, uuid: $scope.invitee}, undefined, function(){ + $scope.invitee = ''; + }, function(){ + $scope.invitee = ''; + }); + }; + }]) + .controller("MemberModalCtrl", ['$scope', '$rootScope', 'Members', 'Shared', '$http', 'Notification', 'Groups', function($scope, $rootScope, Members, Shared, $http, Notification, Groups) { $scope.timestamp = function(timestamp){ diff --git a/public/js/controllers/rootCtrl.js b/public/js/controllers/rootCtrl.js index 65e1188e77..bad8734e37 100644 --- a/public/js/controllers/rootCtrl.js +++ b/public/js/controllers/rootCtrl.js @@ -114,6 +114,7 @@ habitrpg.controller("RootCtrl", ['$scope', '$rootScope', '$location', 'User', '$ templateUrl: 'modals/' + template + '.html', controller: options.controller, // optional scope: options.scope, // optional + resolve: options.resolve, // optional keyboard: (options.keyboard === undefined ? true : options.keyboard), // optional backdrop: (options.backdrop === undefined ? true : options.backdrop), // optional size: options.size, // optional, 'sm' or 'lg' diff --git a/views/options/social/group.jade b/views/options/social/group.jade index 5d50ec3596..0e59b631de 100644 --- a/views/options/social/group.jade +++ b/views/options/social/group.jade @@ -55,7 +55,7 @@ a.pull-right.gem-wallet(ng-if='group.type!="party"', popover-trigger='mouseenter .panel-heading h3.panel-title =env.t('members') - button.pull-right.btn.btn-primary(ng-click="openModal('invite-friends', {controller:'GroupsCtrl'})", ng-if='::group.type=="party"') Invite Friends + button.pull-right.btn.btn-primary(ng-click="openInviteModal(group)") Invite Friends .panel-body.modal-fixed-height div.form-group(ng-if='::group.type=="party"') p=env.t('partyList') @@ -99,14 +99,6 @@ a.pull-right.gem-wallet(ng-if='group.type!="party"', popover-trigger='mouseenter a.media-body span(ng-click='clickMember(invite._id, true)') | {{invite.profile.name}} - .panel-footer(ng-if='::group.type!="party"') - form.form-inline(ng-submit='invite(group)') - //.alert.alert-danger(ng-show='_groupError') {{_groupError}} - .input-group - input.form-control(type='text', placeholder=env.t('userId'), ng-model='group.invitee') - span.input-group-btn - input.btn.btn-default(type='submit', value=env.t('invite')) - a.btn.btn-danger(data-id='{{group.id}}', ng-click='clickLeave(group, $event)')=env.t('leave') diff --git a/views/shared/modals/invite-friends.jade b/views/shared/modals/invite-friends.jade index 02e4ce0c8d..13f954167f 100644 --- a/views/shared/modals/invite-friends.jade +++ b/views/shared/modals/invite-friends.jade @@ -4,10 +4,10 @@ script(type='text/ng-template', id='modals/invite-friends.html') .modal-body p.alert.alert-info Invite friends by User ID here. - form.form-inline(ng-submit='invite(party)') + form.form-inline(ng-submit='invite()') //-.alert.alert-danger(ng-show='_groupError') {{_groupError}} .form-group - input.form-control(type='text', placeholder=env.t('userId'), ng-model='party.invitee') + input.form-control(type='text', placeholder=env.t('userId'), ng-model='invitee') |  button.btn.btn-primary(type='submit') Invite Existing User @@ -15,7 +15,7 @@ script(type='text/ng-template', id='modals/invite-friends.html') p.alert.alert-info Invite friends by email. If they join via your email, they'll automatically be invited to your party. - form.form-horizontal(ng-submit='inviteEmails(inviter, emails)') + form.form-horizontal(ng-submit='inviteEmails()') table.table.table-striped thead tr From 06561bf70f2dda5edee8ea1e1ee66e2cad5a897d Mon Sep 17 00:00:00 2001 From: Matteo Pagliazzi Date: Tue, 10 Feb 2015 19:40:15 +0100 Subject: [PATCH 4/7] finash invites reworking --- public/js/controllers/groupsCtrl.js | 13 +++++---- src/controllers/groups.js | 41 ++++++++++++----------------- src/controllers/user.js | 10 ++++++- src/middleware.js | 3 ++- src/routes/apiv2.coffee | 2 +- 5 files changed, 37 insertions(+), 32 deletions(-) diff --git a/public/js/controllers/groupsCtrl.js b/public/js/controllers/groupsCtrl.js index 1b4fb9b42c..3f27ecd82e 100644 --- a/public/js/controllers/groupsCtrl.js +++ b/public/js/controllers/groupsCtrl.js @@ -97,21 +97,24 @@ habitrpg.controller("GroupsCtrl", ['$scope', '$rootScope', 'Shared', 'Groups', ' } ]) - .controller('InviteToGroupCtrl', ['$scope', 'User', 'Groups', 'injectedGroup', '$http', function($scope, User, Groups, injectedGroup, $http){ $scope.group = injectedGroup; + .controller('InviteToGroupCtrl', ['$scope', 'User', 'Groups', 'injectedGroup', '$http', 'Notification', function($scope, User, Groups, injectedGroup, $http, Notification){ + $scope.group = injectedGroup; $scope.inviter = User.user.profile.name; $scope.emails = [{name:"",email:""},{name:"",email:""}]; - // todo use Groups.Group.invite for everything not raw $http $scope.inviteEmails = function(){ - $http.post('/api/v2/user/social/invite-friends/' + $scope.group._id, {inviter:$scope.inviter, emails:$scope.emails}).success(function(){ - Notification.text("Invitations sent!"); + Groups.Group.invite({gid: $scope.group._id}, {inviter: $scope.inviter, emails: $scope.emails}, function(){ + Notification.text("Invitation(s) sent!"); + $scope.emails = [{name:'',email:''},{name:'',email:''}]; + }, function(){ $scope.emails = [{name:'',email:''},{name:'',email:''}]; }); }; $scope.invite = function(){ - Groups.Group.invite({gid: $scope.group._id, uuid: $scope.invitee}, undefined, function(){ + Groups.Group.invite({gid: $scope.group._id}, {uuids: [$scope.invitee]}, function(){ + Notification.text("Invitation(s) sent!"); $scope.invitee = ''; }, function(){ $scope.invitee = ''; diff --git a/src/controllers/groups.js b/src/controllers/groups.js index 24472b5b30..9003799722 100644 --- a/src/controllers/groups.js +++ b/src/controllers/groups.js @@ -508,9 +508,7 @@ api.leave = function(req, res, next) { }) } -var inviteByUUID = function(uuids, group, req, res, next){ - uuids = Array.isArray(uuids) ? uuids : [uuids]; - +var inviteByUUIDs = function(uuids, group, req, res, next){ async.each(uuids, function(uuid, cb){ User.findById(uuid, function(err,invite){ if (err) return cb(err); @@ -573,7 +571,6 @@ var inviteByUUID = function(uuids, group, req, res, next){ utils.txnEmail(invite, ('invited-' + (group.type == 'guild' ? 'guild' : 'party')), emailVars); } - // TODO what does this cb calls? anything? cb(); }); } @@ -591,7 +588,7 @@ var inviteByUUID = function(uuids, group, req, res, next){ }; -var inviteByEmail = function(invites, group, req, res, next){ +var inviteByEmails = function(invites, group, req, res, next){ var usersAlreadyRegistered = []; async.each(invites, function(invite, cb){ @@ -608,35 +605,32 @@ var inviteByEmail = function(invites, group, req, res, next){ return cb(); } - var link = nconf.get('BASE_URL')+'?groupInvite='+ utils.encrypt(JSON.stringify({id:group._id, inviter:res.locals.user._id, name:group.name})); + // yeah, it supports guild too but for backward compatibility we'll use partyInvite as query + var link = nconf.get('BASE_URL')+'?partyInvite='+ utils.encrypt(JSON.stringify({id:group._id, inviter:res.locals.user._id, name:group.name})); var variables = [ {name: 'LINK', content: link}, {name: 'INVITER', content: req.body.inviter || utils.getUserInfo(res.locals.user, ['name']).name} ]; - // We check for unsubscribeFromAll here because don't pass through utils.getUserInfo - // Todo now this should be only for non registered users so no need to check preferences - if(!userToContact || - (invite.preferences.emailNotifications['invited' + (group.type == 'guild' ? 'Guild' : 'Party')] !== false && - userToContact.preferences.emailNotifications.unsubscribeFromAll !== true)){ - // TODO implement "users can only be invited once" - invite.canSend = true; - utils.txnEmail(invite, 'invite-friend', variables); - } + // TODO implement "users can only be invited once" + invite.canSend = true; // Requested by utils.txnEmail + utils.txnEmail(invite, ('invite-friend' + (group.type == 'guild' ? '-guild' : '')), variables); cb(); }); }else{ - cb('Email address is required.'); + cb({code: 400, err: 'Email address is required.'}); } }, function(err){ - if(err) return next(err); + if(err) return err.code ? res.json(err.code, {err: err.err}) : next(err); if(usersAlreadyRegistered.length > 0){ - inviteByUUID(usersAlreadyRegistered, group, req, res, next); + inviteByUUIDs(usersAlreadyRegistered, group, req, res, next); }else{ - // todo send back group here as we do when inviting by uuid? + + // Send only status code down the line because it doesn't need + // info on invited users since they are not yet registered res.send(200); } }); @@ -644,12 +638,11 @@ var inviteByEmail = function(invites, group, req, res, next){ api.invite = function(req, res, next){ var group = res.locals.group; - var invitationType = req.query.invitationType; - if(invitationType == 'uuid'){ - inviteByUUID(req.query.uuid, group, req, res, next); - }else if(invitationType == 'email'){ - inviteByEmail(req.body.emails, group, req, res, next) + if(req.body.uuids){ + inviteByUUIDs(req.body.uuids, group, req, res, next); + }else if(req.body.emails){ + inviteByEmails(req.body.emails, group, req, res, next) }else{ return res.json(400,{err: "Can invite only by email or uuid"}); } diff --git a/src/controllers/user.js b/src/controllers/user.js index 09c27ddd89..d3fd377e63 100644 --- a/src/controllers/user.js +++ b/src/controllers/user.js @@ -409,13 +409,14 @@ api.cast = function(req, res, next) { } } +// It supports guild too now but we'll stick to partyInvite for backward compatibility api.sessionPartyInvite = function(req,res,next){ if (!req.session.partyInvite) return next(); var inv = res.locals.user.invitations; if (inv.party && inv.party.id) return next(); // already invited to a party async.waterfall([ function(cb){ - Group.findOne({_id:req.session.partyInvite.id, type:'party', members:{$in:[req.session.partyInvite.inviter]}}) + Group.findOne({_id:req.session.partyInvite.id, members:{$in:[req.session.partyInvite.inviter]}}) .select('invites members').exec(cb); }, function(group, cb){ @@ -424,6 +425,13 @@ api.sessionPartyInvite = function(req,res,next){ delete req.session.partyInvite; return cb(); } + + if(group.type === 'guild'){ + inv.guilds.push(req.session.partyInvite); + }else{ + //req.body.type in 'guild', 'party' + inv.party = req.session.partyInvite; + } inv.party = req.session.partyInvite; delete req.session.partyInvite; if (!~group.invites.indexOf(res.locals.user._id)) diff --git a/src/middleware.js b/src/middleware.js index 0c6c70d5d8..a3b3f092ba 100644 --- a/src/middleware.js +++ b/src/middleware.js @@ -201,7 +201,8 @@ module.exports.locals = function(req, res, next) { worldDmg: (tavern && tavern.quest && tavern.quest.extra && tavern.quest.extra.worldDmg) || {} }); - // Put query-string party invitations into session to be handled later + // Put query-string party (& guild but use partyInvite for backward compatibility) + // invitations into session to be handled later try{ req.session.partyInvite = JSON.parse(utils.decrypt(req.query.partyInvite)) } catch(e){} diff --git a/src/routes/apiv2.coffee b/src/routes/apiv2.coffee index 2c8703734b..acfa448f53 100644 --- a/src/routes/apiv2.coffee +++ b/src/routes/apiv2.coffee @@ -460,7 +460,7 @@ module.exports = (swagger, v2) -> description: "Invite a user to a group" parameters: [ path 'gid','Group id','string' - query 'invitationType','The type of invitation to send (uuid or email)','string' + body '','a payload of invites either under body.uuids or body.emails, only one of them!','object' ] middleware: [auth.auth, i18n.getUserLanguage, groups.attachGroup] action:groups.invite From 0d23ef94da2d595c18fb49e18553c9f86e22e4c8 Mon Sep 17 00:00:00 2001 From: Matteo Pagliazzi Date: Tue, 10 Feb 2015 21:42:43 +0100 Subject: [PATCH 5/7] fix when second email not defined --- src/controllers/groups.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/controllers/groups.js b/src/controllers/groups.js index 9003799722..52389f1234 100644 --- a/src/controllers/groups.js +++ b/src/controllers/groups.js @@ -620,7 +620,7 @@ var inviteByEmails = function(invites, group, req, res, next){ cb(); }); }else{ - cb({code: 400, err: 'Email address is required.'}); + cb(); } }, function(err){ if(err) return err.code ? res.json(err.code, {err: err.err}) : next(err); From be276461437838b6ca96456d914facceff8967ef Mon Sep 17 00:00:00 2001 From: Matteo Pagliazzi Date: Tue, 10 Feb 2015 21:53:26 +0100 Subject: [PATCH 6/7] correctly fetch group.type --- src/controllers/user.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/controllers/user.js b/src/controllers/user.js index d3fd377e63..e7125c51c0 100644 --- a/src/controllers/user.js +++ b/src/controllers/user.js @@ -417,7 +417,7 @@ api.sessionPartyInvite = function(req,res,next){ async.waterfall([ function(cb){ Group.findOne({_id:req.session.partyInvite.id, members:{$in:[req.session.partyInvite.inviter]}}) - .select('invites members').exec(cb); + .select('invites members type').exec(cb); }, function(group, cb){ if (!group){ @@ -426,7 +426,7 @@ api.sessionPartyInvite = function(req,res,next){ return cb(); } - if(group.type === 'guild'){ + if(group.type == 'guild'){ inv.guilds.push(req.session.partyInvite); }else{ //req.body.type in 'guild', 'party' From 9c6fc78a2fe6791d26796f58d02237cc67e9bd12 Mon Sep 17 00:00:00 2001 From: Matteo Pagliazzi Date: Tue, 10 Feb 2015 22:07:36 +0100 Subject: [PATCH 7/7] invite friend to guild: pass guild name --- src/controllers/groups.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/controllers/groups.js b/src/controllers/groups.js index 52389f1234..a98fb8e1bc 100644 --- a/src/controllers/groups.js +++ b/src/controllers/groups.js @@ -613,6 +613,10 @@ var inviteByEmails = function(invites, group, req, res, next){ {name: 'INVITER', content: req.body.inviter || utils.getUserInfo(res.locals.user, ['name']).name} ]; + if(group.type == 'guild'){ + variables.push({name: 'GUILD_NAME', content: group.name}); + } + // TODO implement "users can only be invited once" invite.canSend = true; // Requested by utils.txnEmail utils.txnEmail(invite, ('invite-friend' + (group.type == 'guild' ? '-guild' : '')), variables);