Merge pull request #4238 from HabitRPG/invite-friends

Invite friends
This commit is contained in:
Tyler Renelle
2014-11-13 13:04:20 -07:00
10 changed files with 125 additions and 12 deletions
+1
View File
@@ -44,6 +44,7 @@
"paypal-ipn": "~1.0.1",
"paypal-recurring": "git://github.com/jaybryant/paypal-recurring#656b496f43440893c984700191666a5c5c535dca",
"pretty-data": "git://github.com/vkiryukhin/pretty-data#master",
"qs": "^2.3.2",
"request": "~2.44.0",
"s3-upload-stream": "^1.0.6",
"stripe": "*",
+15 -3
View File
@@ -1,7 +1,7 @@
"use strict";
habitrpg.controller("GroupsCtrl", ['$scope', '$rootScope', 'Shared', 'Groups', '$http', '$q', 'User', 'Members', '$state',
function($scope, $rootScope, Shared, Groups, $http, $q, User, Members, $state) {
habitrpg.controller("GroupsCtrl", ['$scope', '$rootScope', 'Shared', 'Groups', '$http', '$q', 'User', 'Members', '$state', 'Notification',
function($scope, $rootScope, Shared, Groups, $http, $q, User, Members, $state, Notification) {
$scope.isMemberOfPendingQuest = function(userid, group) {
if (!group.quest || !group.quest.members) return false;
if (group.quest.active) return false; // quest is started, not pending
@@ -63,7 +63,7 @@ habitrpg.controller("GroupsCtrl", ['$scope', '$rootScope', 'Shared', 'Groups', '
}
}
// ------ Invites ------
// ------ Invites ------
$scope.invite = function(group){
Groups.Group.invite({gid: group._id, uuid: group.invitee}, undefined, function(){
@@ -72,6 +72,18 @@ habitrpg.controller("GroupsCtrl", ['$scope', '$rootScope', 'Shared', 'Groups', '
group.invitee = '';
});
}
$scope.emails = [{name:"",email:""},{name:"",email:""}];
//$scope.inviteLink = function(obj){
// return window.env.BASE_URL + '?partyInvite=' + encodeURIComponent(JSON.stringify(obj));
//}
$scope.inviteEmails = function(emails){
$http.post('/api/v2/user/social/invite-friends', emails).success(function(){
Notification.text("Invitations sent!");
$scope.emails = [{name:'',email:''},{name:'',email:''}];
});
}
}
])
+4 -3
View File
@@ -300,7 +300,8 @@ api.join = function(req, res, next) {
group = res.locals.group;
if (group.type == 'party' && group._id == (user.invitations && user.invitations.party && user.invitations.party.id)) {
user.invitations.party = undefined;
User.update({_id:user.invitations.party.inviter}, {$inc:{'items.quests.basilist':1}}).exec(); // Reward inviter
user.invitations.party = undefined; // Clear invite
user.save();
// invite new user to pending quest
if (group.quest.key && !group.quest.active) {
@@ -439,10 +440,10 @@ api.invite = function(req, res, next) {
function sendInvite (){
if(group.type === 'guild'){
invite.invitations.guilds.push({id: group._id, name: group.name});
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}
invite.invitations.party = {id: group._id, name: group.name, inviter:res.locals.user._id};
}
group.invites.push(invite._id);
+37 -1
View File
@@ -7,13 +7,15 @@ var nconf = require('nconf');
var async = require('async');
var shared = require('habitrpg-shared');
var User = require('./../models/user').model;
var ga = require('./../utils').ga;
var utils = require('./../utils');
var ga = utils.ga;
var Group = require('./../models/group').model;
var Challenge = require('./../models/challenge').model;
var moment = require('moment');
var logging = require('./../logging');
var acceptablePUTPaths;
var api = module.exports;
var qs = require('qs');
// api.purchase // Shared.ops
@@ -393,6 +395,40 @@ 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);
var link = nconf.get('BASE_URL') + '?' + qs.stringify({partyInvite:{id:party._id, inviter:res.locals.user._id, name:party.name}});
_.each(req.body, function(invite){
if (invite.email) {
var variables = [
{name: 'LINK', content: link},
{name: 'INVITER', content: res.locals.user.profile.name},
{name: 'INVITEE', content: invite.name}
];
// 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) {
var inv = res.locals.user.invitations;
if (!(inv.party && inv.party.id)) {
inv.party = req.session.partyInvite;
Group.update({_id:req.session.partyInvite.id},{$addToSet:{invites:res.locals.user._id}});
delete req.session.partyInvite;
return res.locals.user.save(next);
}
}
next();
}
/**
* All other user.ops which can easily be mapped to habitrpg-shared/index.coffee, not requiring custom API-wrapping
*/
+7 -1
View File
@@ -12,6 +12,7 @@ var shared = require('habitrpg-shared');
var request = require('request');
var os = require('os');
var moment = require('moment');
var qs = require('qs');
module.exports.apiThrottle = function(app) {
if (nconf.get('NODE_ENV') !== 'production') return;
@@ -196,7 +197,12 @@ module.exports.locals = function(req, res, next) {
tavern: tavern, // for world boss
worldDmg: (tavern && tavern.quest && tavern.quest.extra && tavern.quest.extra.worldDmg) || {}
}
};
// Put query-string party invitations into session to be handled later
var partyInvite = qs.parse(req.query.partyInvite);
if (partyInvite && partyInvite.id)
req.session.partyInvite = partyInvite;
next();
}
+10 -1
View File
@@ -320,7 +320,7 @@ module.exports = (swagger, v2) ->
parameters:[
body '','The array of batch-operations to perform','object'
]
middleware: [middleware.forceRefresh, auth.auth, i18n.getUserLanguage, cron]
middleware: [middleware.forceRefresh, auth.auth, i18n.getUserLanguage, cron, user.sessionPartyInvite]
action: user.batchUpdate
# Tags
@@ -364,6 +364,15 @@ 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
# ---------------------------------
# Groups
# ---------------------------------
+1
View File
@@ -63,6 +63,7 @@ script(type='text/ng-template', id='partials/options.settings.settings.html')
button.btn.btn-default(ng-click='showTour()', popover-placement='right', popover-trigger='mouseenter', popover=env.t('restartTour'))= env.t('showTour')
button.btn.btn-default(ng-click='showBailey()', popover-trigger='mouseenter', popover-placement='right', popover=env.t('showBaileyPop'))= env.t('showBailey')
button.btn.btn-default(ng-click='openRestoreModal()', popover-trigger='mouseenter', popover-placement='right', popover=env.t('fixValPop'))= env.t('fixVal')
button.btn.btn-default(ng-click="openModal('invite-friends', {controller:'GroupsCtrl'})") Invite Friends
button.btn.btn-default(ng-if='user.preferences.disableClasses==true', ng-click='user.ops.changeClass({})', popover-trigger='mouseenter', popover-placement='right', popover=env.t('enableClassPop'))= env.t('enableClass')
button.btn.btn-default(ng-if='!user.preferences.disableClasses && user.flags.classSelected', ng-click='showClassesTour()', popover-trigger='mouseenter', popover-placement='right', popover=env.t('classTourPop'))= env.t('showClass')
+5 -3
View File
@@ -48,9 +48,11 @@ a.pull-right.gem-wallet(ng-if='group.type!="party"', popover-trigger='mouseenter
// ------ Members -------
.panel.panel-default
.panel-heading
h3.panel-title=env.t('members')
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
.panel-body.modal-fixed-height
div(ng-if='group.type=="party"')
div(ng-if='::group.type=="party"')
=env.t('partyList')
br
select#partyOrder(
@@ -86,7 +88,7 @@ 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
.panel-footer(ng-if='::group.type!="party"')
form.form-inline(ng-submit='invite(group)')
//.alert.alert-danger(ng-show='_groupError') {{_groupError}}
.form-group
+1
View File
@@ -10,3 +10,4 @@ include ./classes
include ./quests
include ./rebirth
include ./limited
include ./invite-friends
+44
View File
@@ -0,0 +1,44 @@
script(type='text/ng-template', id='modals/invite-friends.html')
.modal-header
h4 Invite Friends
.modal-body
p.alert.alert-info Invite friends by <a href='http://habitrpg.wikia.com/wiki/API_Options' target='_blank'>User ID</a> here.
form.form-inline(ng-submit='invite(party)')
//-.alert.alert-danger(ng-show='_groupError') {{_groupError}}
.form-group
input.form-control(type='text', placeholder=env.t('userId'), ng-model='party.invitee')
|&nbsp;
button.btn.btn-primary(type='submit') Invite Existing User
hr
p.alert.alert-info Invite friends by email. If they join via your email, they'll automatically be invited to your party.
table.table.table-striped
thead
tr
th Name
th Email
tbody
tr(ng-repeat='email in emails')
td
input.form-control(type='text', ng-model='email.name')
td
input.form-control(type='email', ng-model='email.email')
tr
td(colspan=2)
button.btn.btn-xs.pull-right(ng-click='emails = emails.concat([{name:"",email:""}])')
i.glyphicon.glyphicon-plus
tr
td(colspan=2)
button.btn.btn-primary.pull-right(ng-click='inviteEmails(emails)') Invite New User(s)
//-
hr
p.alert.alert-info Or share this link (copy/paste):
input.form-control(type='text', ng-value='inviteLink({id: party._id, inviter: user._id, name: party.name})')
.modal-footer
button.btn.btn-default(ng-click='$close()') Close