Merge in develop
This commit is contained in:
@@ -62,7 +62,7 @@ api.authWithUrl = function(req, res, next) {
|
||||
if (_.isEmpty(user)) return res.json(401, NO_USER_FOUND);
|
||||
res.locals.user = user;
|
||||
next();
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
api.registerUser = function(req, res, next) {
|
||||
|
||||
@@ -11,7 +11,7 @@ var logging = require('./../logging');
|
||||
var csv = require('express-csv');
|
||||
var utils = require('../utils');
|
||||
var api = module.exports;
|
||||
|
||||
var pushNotify = require('./pushNotifications');
|
||||
|
||||
/*
|
||||
------------------------------------------------------------------------
|
||||
@@ -358,6 +358,9 @@ api.selectWinner = function(req, res, next) {
|
||||
{name: 'CHALLENGE_NAME', content: chal.name}
|
||||
]);
|
||||
}
|
||||
|
||||
pushNotify.sendNotify(saved, shared.i18n.t('wonChallenge'), chal.name);
|
||||
|
||||
closeChal(cid, {broken: 'CHALLENGE_CLOSED', winner: saved.profile.name}, cb);
|
||||
}
|
||||
], function(err){
|
||||
|
||||
@@ -15,6 +15,7 @@ var Challenge = require('./../models/challenge').model;
|
||||
var EmailUnsubscription = require('./../models/emailUnsubscription').model;
|
||||
var isProd = nconf.get('NODE_ENV') === 'production';
|
||||
var api = module.exports;
|
||||
var pushNotify = require('./pushNotifications');
|
||||
|
||||
/*
|
||||
------------------------------------------------------------------------
|
||||
@@ -136,8 +137,36 @@ api.get = function(req, res, next) {
|
||||
populateQuery(gid, q);
|
||||
q.exec(function(err, group){
|
||||
if (err) return next(err);
|
||||
if (!group && gid!=='party') return res.json(404,{err: "Group not found or you don't have access."});
|
||||
res.json(group);
|
||||
if(!group){
|
||||
if(gid !== 'party') return res.json(404,{err: "Group not found or you don't have access."});
|
||||
|
||||
// Don't send a 404 when querying for a party even if it doesn't exist
|
||||
// so that users with no party don't get a 404 on every access to the site
|
||||
return res.json(group);
|
||||
}
|
||||
//Since we have a limit on how many members are populate to the group, we want to make sure the user is always in the group
|
||||
var userInGroup = _.find(group.members, function(member){ return member._id == user._id; });
|
||||
//If the group is private or the group is a party, then the user must be a member of the group based on access restrictions above
|
||||
if (group.privacy === 'private' || gid === 'party') {
|
||||
//If the user is not in the group query, remove a user and add the current user
|
||||
if (!userInGroup) {
|
||||
group.members.splice(0,1);
|
||||
group.members.push(user);
|
||||
}
|
||||
res.json(group);
|
||||
} else if ( group.privacy === "public" ) { //The group is public, we must do an extra check to see if the user is already in the group query
|
||||
//We must see how to check if a user is a member of a public group, so we requery
|
||||
var q2 = Group.findOne({ _id: group._id, privacy:'public', members: {$in:[user._id]} });
|
||||
q2.exec(function(err, group2){
|
||||
if (err) return next(err);
|
||||
if (group2 && !userInGroup) {
|
||||
group.members.splice(0,1);
|
||||
group.members.push(user);
|
||||
}
|
||||
res.json(group);
|
||||
});
|
||||
}
|
||||
|
||||
gid = null;
|
||||
});
|
||||
};
|
||||
@@ -309,7 +338,8 @@ api.flagChatMessage = function(req, res, next){
|
||||
group.markModified('chat');
|
||||
group.save(function(err,_saved){
|
||||
if(err) return next(err);
|
||||
var addressesToSendTo = JSON.parse(nconf.get('FLAG_REPORT_EMAIL'));
|
||||
var addressesToSendTo = nconf.get('FLAG_REPORT_EMAIL');
|
||||
addressesToSendTo = (typeof addressesToSendTo == 'string') ? JSON.parse(addressesToSendTo) : addressesToSendTo;
|
||||
|
||||
if(Array.isArray(addressesToSendTo)){
|
||||
addressesToSendTo = addressesToSendTo.map(function(email){
|
||||
@@ -326,17 +356,17 @@ api.flagChatMessage = function(req, res, next){
|
||||
{name: "REPORTER_USERNAME", content: user.profile.name},
|
||||
{name: "REPORTER_UUID", content: user._id},
|
||||
{name: "REPORTER_EMAIL", content: user.auth.local ? user.auth.local.email : ((user.auth.facebook && user.auth.facebook.emails && user.auth.facebook.emails[0]) ? user.auth.facebook.emails[0].value : null)},
|
||||
{name: "REPORTER_MODAL_URL", content: "https://habitrpg.com/static/front/#?memberId=" + user._id},
|
||||
{name: "REPORTER_MODAL_URL", content: "/static/front/#?memberId=" + user._id},
|
||||
|
||||
{name: "AUTHOR_USERNAME", content: message.user},
|
||||
{name: "AUTHOR_UUID", content: message.uuid},
|
||||
{name: "AUTHOR_EMAIL", content: author.auth.local ? author.auth.local.email : ((author.auth.facebook && author.auth.facebook.emails && author.auth.facebook.emails[0]) ? author.auth.facebook.emails[0].value : null)},
|
||||
{name: "AUTHOR_MODAL_URL", content: "https://habitrpg.com/static/front/#?memberId=" + message.uuid},
|
||||
{name: "AUTHOR_MODAL_URL", content: "/static/front/#?memberId=" + message.uuid},
|
||||
|
||||
{name: "GROUP_NAME", content: group.name},
|
||||
{name: "GROUP_TYPE", content: group.type},
|
||||
{name: "GROUP_ID", content: group._id},
|
||||
{name: "GROUP_URL", content: group._id == 'habitrpg' ? (nconf.get('BASE_URL') + '/#/options/groups/tavern') : (group.type === 'guild' ? (nconf.get('BASE_URL')+ '/#/options/groups/guilds/' + group._id) : 'party')},
|
||||
{name: "GROUP_URL", content: group._id == 'habitrpg' ? '/#/options/groups/tavern' : (group.type === 'guild' ? ('/#/options/groups/guilds/' + group._id) : 'party')},
|
||||
]);
|
||||
|
||||
return res.send(204);
|
||||
@@ -398,7 +428,8 @@ api.likeChatMessage = function(req, res, next) {
|
||||
|
||||
api.join = function(req, res, next) {
|
||||
var user = res.locals.user,
|
||||
group = res.locals.group;
|
||||
group = res.locals.group,
|
||||
isUserInvited = false;
|
||||
|
||||
if (group.type == 'party' && group._id == (user.invitations && user.invitations.party && user.invitations.party.id)) {
|
||||
User.update({_id:user.invitations.party.inviter}, {$inc:{'items.quests.basilist':1}}).exec(); // Reward inviter
|
||||
@@ -409,16 +440,25 @@ api.join = function(req, res, next) {
|
||||
group.quest.members[user._id] = undefined;
|
||||
group.markModified('quest.members');
|
||||
}
|
||||
}
|
||||
else if (group.type == 'guild' && user.invitations && user.invitations.guilds) {
|
||||
isUserInvited = true;
|
||||
} else if (group.type == 'guild' && user.invitations && user.invitations.guilds) {
|
||||
var i = _.findIndex(user.invitations.guilds, {id:group._id});
|
||||
if (~i) user.invitations.guilds.splice(i,1);
|
||||
user.save();
|
||||
if (~i){
|
||||
isUserInvited = true;
|
||||
user.invitations.guilds.splice(i,1);
|
||||
user.save();
|
||||
}else{
|
||||
isUserInvited = group.privacy === 'private' ? false : true;
|
||||
}
|
||||
}
|
||||
|
||||
if(!isUserInvited) return res.json(401, {err: "Can't join a group you're not invited to."});
|
||||
|
||||
if (!_.contains(group.members, user._id)){
|
||||
group.members.push(user._id);
|
||||
group.invites.splice(_.indexOf(group.invites, user._id), 1);
|
||||
if (group.invites.length > 0) {
|
||||
group.invites.splice(_.indexOf(group.invites, user._id), 1);
|
||||
}
|
||||
}
|
||||
|
||||
async.series([
|
||||
@@ -430,7 +470,6 @@ api.join = function(req, res, next) {
|
||||
}
|
||||
], function(err, results){
|
||||
if (err) return next(err);
|
||||
|
||||
// Return the group? Or not?
|
||||
res.json(results[1]);
|
||||
group = null;
|
||||
@@ -540,9 +579,13 @@ var inviteByUUIDs = function(uuids, group, req, res, next){
|
||||
function sendInvite (){
|
||||
if(group.type === 'guild'){
|
||||
invite.invitations.guilds.push({id: group._id, name: group.name, inviter:res.locals.user._id});
|
||||
|
||||
pushNotify.sendNotify(invite, shared.i18n.t('invitedGuild'), group.name);
|
||||
}else{
|
||||
//req.body.type in 'guild', 'party'
|
||||
invite.invitations.party = {id: group._id, name: group.name, inviter:res.locals.user._id};
|
||||
|
||||
pushNotify.sendNotify(invite, shared.i18n.t('invitedParty'), group.name);
|
||||
}
|
||||
|
||||
group.invites.push(invite._id);
|
||||
@@ -567,12 +610,12 @@ var inviteByUUIDs = function(uuids, group, req, res, next){
|
||||
if(group.type == 'guild'){
|
||||
emailVars.push(
|
||||
{name: 'GUILD_NAME', content: group.name},
|
||||
{name: 'GUILD_URL', content: nconf.get('BASE_URL') + '/#/options/groups/guilds/public'}
|
||||
{name: 'GUILD_URL', content: '/#/options/groups/guilds/public'}
|
||||
);
|
||||
}else{
|
||||
emailVars.push(
|
||||
{name: 'PARTY_NAME', content: group.name},
|
||||
{name: 'PARTY_URL', content: nconf.get('BASE_URL') + '/#/options/groups/party'}
|
||||
{name: 'PARTY_URL', content: '/#/options/groups/party'}
|
||||
)
|
||||
}
|
||||
|
||||
@@ -614,7 +657,7 @@ var inviteByEmails = function(invites, group, req, res, next){
|
||||
}
|
||||
|
||||
// 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 link = '?partyInvite='+ utils.encrypt(JSON.stringify({id:group._id, inviter:res.locals.user._id, name:group.name}));
|
||||
|
||||
var inviterVars = utils.getUserInfo(res.locals.user, ['name', 'email']);
|
||||
var variables = [
|
||||
@@ -679,8 +722,8 @@ api.removeMember = function(req, res, next){
|
||||
utils.txnEmail(removedUser, ('kicked-from-' + group.type), [
|
||||
{name: 'GROUP_NAME', content: group.name},
|
||||
{name: 'MESSAGE', content: message},
|
||||
{name: 'GUILDS_LINK', content: nconf.get('BASE_URL') + '/#/options/groups/guilds/public'},
|
||||
{name: 'PARTY_WANTED_GUILD', content: nconf.get('BASE_URL') + '/#/options/groups/guilds/f2db2a7f-13c5-454d-b3ee-ea1f5089e601'}
|
||||
{name: 'GUILDS_LINK', content: '/#/options/groups/guilds/public'},
|
||||
{name: 'PARTY_WANTED_GUILD', content: '/#/options/groups/guilds/f2db2a7f-13c5-454d-b3ee-ea1f5089e601'}
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -830,7 +873,7 @@ questStart = function(req, res, next) {
|
||||
});
|
||||
|
||||
utils.txnEmail(usersToEmail, 'quest-started', [
|
||||
{name: 'PARTY_URL', content: nconf.get('BASE_URL') + '/#/options/groups/party'}
|
||||
{name: 'PARTY_URL', content: '/#/options/groups/party'}
|
||||
]);
|
||||
|
||||
_.each(groupClone.members, function(user){
|
||||
@@ -870,6 +913,10 @@ api.questAccept = function(req, res, next) {
|
||||
group.quest.leader = user._id;
|
||||
} else {
|
||||
group.quest.members[m] = undefined;
|
||||
|
||||
User.findById(m, function(err,groupMember){
|
||||
pushNotify.sendNotify(groupMember, shared.i18n.t('questInvitationTitle'), shared.i18n.t('questInvitationInfo', { quest: quest.text() }));
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@@ -890,7 +937,7 @@ api.questAccept = function(req, res, next) {
|
||||
{name: 'QUEST_NAME', content: quest.text()},
|
||||
{name: 'INVITER', content: inviterVars.name},
|
||||
{name: 'REPLY_TO_ADDRESS', content: inviterVars.email},
|
||||
{name: 'PARTY_URL', content: nconf.get('BASE_URL') + '/#/options/groups/party'}
|
||||
{name: 'PARTY_URL', content: '/#/options/groups/party'}
|
||||
]);
|
||||
|
||||
questStart(req,res,next);
|
||||
|
||||
@@ -7,6 +7,7 @@ var _ = require('lodash');
|
||||
var shared = require('../../../common');
|
||||
var utils = require('../utils');
|
||||
var nconf = require('nconf');
|
||||
var pushNotify = require('./pushNotifications');
|
||||
|
||||
var fetchMember = function(uuid, restrict){
|
||||
return function(cb){
|
||||
@@ -72,7 +73,7 @@ api.sendPrivateMessage = function(req, res, next){
|
||||
if(fetchedMember.preferences.emailNotifications.newPM !== false){
|
||||
utils.txnEmail(fetchedMember, 'new-pm', [
|
||||
{name: 'SENDER', content: utils.getUserInfo(res.locals.user, ['name']).name},
|
||||
{name: 'PMS_INBOX_URL', content: nconf.get('BASE_URL') + '/#/options/groups/inbox'}
|
||||
{name: 'PMS_INBOX_URL', content: '/#/options/groups/inbox'}
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -96,12 +97,18 @@ api.sendGift = function(req, res, next){
|
||||
member.balance += amt;
|
||||
user.balance -= amt;
|
||||
api.sendMessage(user, member, req.body);
|
||||
|
||||
var byUsername = utils.getUserInfo(user, ['name']).name;
|
||||
|
||||
if(member.preferences.emailNotifications.giftedGems !== false){
|
||||
utils.txnEmail(member, 'gifted-gems', [
|
||||
{name: 'GIFTER', content: utils.getUserInfo(user, ['name']).name},
|
||||
{name: 'GIFTER', content: byUsername},
|
||||
{name: 'X_GEMS_GIFTED', content: req.body.gems.amount}
|
||||
]);
|
||||
}
|
||||
|
||||
pushNotify.sendNotify(member, shared.i18n.t('giftedGems'), shared.i18n.t('giftedGemsInfo', { amount: req.body.gems.amount, name: byUsername }));
|
||||
|
||||
return async.parallel([
|
||||
function (cb2) { member.save(cb2) },
|
||||
function (cb2) { user.save(cb2) }
|
||||
|
||||
@@ -12,6 +12,7 @@ var async = require('async');
|
||||
var iap = require('./iap');
|
||||
var mongoose= require('mongoose');
|
||||
var cc = require('coupon-code');
|
||||
var pushNotify = require('./../pushNotifications');
|
||||
|
||||
function revealMysteryItems(user) {
|
||||
_.each(shared.content.gear.flat, function(item) {
|
||||
@@ -75,12 +76,19 @@ exports.createSubscription = function(data, cb) {
|
||||
data.user.purchased.txnCount++;
|
||||
if (data.gift){
|
||||
members.sendMessage(data.user, data.gift.member, data.gift);
|
||||
|
||||
var byUserName = utils.getUserInfo(data.user, ['name']).name;
|
||||
|
||||
if(data.gift.member.preferences.emailNotifications.giftedSubscription !== false){
|
||||
utils.txnEmail(data.gift.member, 'gifted-subscription', [
|
||||
{name: 'GIFTER', content: utils.getUserInfo(data.user, ['name']).name},
|
||||
{name: 'GIFTER', content: byUserName},
|
||||
{name: 'X_MONTHS_SUBSCRIPTION', content: months}
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
if (data.gift.member._id != data.user._id) { // Only send push notifications if sending to a user other than yourself
|
||||
pushNotify.sendNotify(data.gift.member, shared.i18n.t('giftedSubscription'), months + " months - by "+ byUserName);
|
||||
}
|
||||
}
|
||||
async.parallel([
|
||||
function(cb2){data.user.save(cb2)},
|
||||
@@ -119,13 +127,20 @@ exports.buyGems = function(data, cb) {
|
||||
utils.ga.transaction(data.user._id, amt).item(amt, 1, data.paymentMethod.toLowerCase() + "-checkout", "Gems > " + data.paymentMethod).send();
|
||||
}
|
||||
if (data.gift){
|
||||
var byUsername = utils.getUserInfo(data.user, ['name']).name;
|
||||
var gemAmount = data.gift.gems.amount || 20;
|
||||
|
||||
members.sendMessage(data.user, data.gift.member, data.gift);
|
||||
if(data.gift.member.preferences.emailNotifications.giftedGems !== false){
|
||||
utils.txnEmail(data.gift.member, 'gifted-gems', [
|
||||
{name: 'GIFTER', content: utils.getUserInfo(data.user, ['name']).name},
|
||||
{name: 'X_GEMS_GIFTED', content: data.gift.gems.amount || 20}
|
||||
{name: 'GIFTER', content: byUsername},
|
||||
{name: 'X_GEMS_GIFTED', content: gemAmount}
|
||||
]);
|
||||
}
|
||||
|
||||
if (data.gift.member._id != data.user._id) { // Only send push notifications if sending to a user other than yourself
|
||||
pushNotify.sendNotify(data.gift.member, shared.i18n.t('giftedGems'), gemAmount + ' Gems - by '+byUsername);
|
||||
}
|
||||
}
|
||||
async.parallel([
|
||||
function(cb2){data.user.save(cb2)},
|
||||
@@ -153,4 +168,4 @@ exports.paypalCheckoutSuccess = paypal.executePayment;
|
||||
exports.paypalIPN = paypal.ipn;
|
||||
|
||||
exports.iapAndroidVerify = iap.androidVerify;
|
||||
exports.iapIosVerify = iap.iosVerify;
|
||||
exports.iapIosVerify = iap.iosVerify;
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
var api = module.exports;
|
||||
var _ = require('lodash');
|
||||
var nconf = require('nconf');
|
||||
|
||||
var pushNotify = require('push-notify');
|
||||
|
||||
var gcmApiKey = nconf.get("PUSH_CONFIGS:GCM_SERVER_API_KEY");
|
||||
|
||||
var gcm = gcmApiKey ? pushNotify.gcm({
|
||||
apiKey: gcmApiKey,
|
||||
retries: 3
|
||||
}) : undefined;
|
||||
|
||||
if(gcm){
|
||||
gcm.on('transmitted', function (result, message, registrationId) {
|
||||
console.info("transmitted", result, message, registrationId);
|
||||
});
|
||||
|
||||
gcm.on('transmissionError', function (error, message, registrationId) {
|
||||
console.info("transmissionError", error, message, registrationId);
|
||||
});
|
||||
gcm.on('updated', function (result, registrationId) {
|
||||
console.info("updated", result, registrationId);
|
||||
});
|
||||
}
|
||||
|
||||
api.sendNotify = function(user, title, msg, timeToLive){
|
||||
timeToLive = timeToLive || 15;
|
||||
|
||||
// need investigation:
|
||||
// https://github.com/HabitRPG/habitrpg/issues/5252
|
||||
if(!user)
|
||||
return;
|
||||
|
||||
_.forEach(user.pushDevices, function(pushDevice){
|
||||
switch(pushDevice.type){
|
||||
case "android":
|
||||
if(gcm){
|
||||
gcm.send({
|
||||
registrationId: pushDevice.regId,
|
||||
//collapseKey: 'COLLAPSE_KEY',
|
||||
delayWhileIdle: true,
|
||||
timeToLive: timeToLive,
|
||||
data: {
|
||||
title: title,
|
||||
message: msg
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case "ios":
|
||||
break;
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -198,7 +198,8 @@ module.exports.locals = function(req, res, next) {
|
||||
Content: shared.content,
|
||||
mods: require('./models/user').mods,
|
||||
tavern: tavern, // for world boss
|
||||
worldDmg: (tavern && tavern.quest && tavern.quest.extra && tavern.quest.extra.worldDmg) || {}
|
||||
worldDmg: (tavern && tavern.quest && tavern.quest.extra && tavern.quest.extra.worldDmg) || {},
|
||||
_: _
|
||||
});
|
||||
|
||||
// Put query-string party (& guild but use partyInvite for backward compatibility)
|
||||
|
||||
@@ -393,7 +393,12 @@ var UserSchema = new Schema({
|
||||
todos: {type:[TaskSchemas.TodoSchema]},
|
||||
rewards: {type:[TaskSchemas.RewardSchema]},
|
||||
|
||||
extra: Schema.Types.Mixed
|
||||
extra: Schema.Types.Mixed,
|
||||
|
||||
pushDevices: {type: [{
|
||||
regId: {type: String},
|
||||
type: {type: String}
|
||||
}],'default': []}
|
||||
|
||||
}, {
|
||||
strict: true,
|
||||
|
||||
@@ -396,6 +396,16 @@ module.exports = (swagger, v2) ->
|
||||
]
|
||||
action: user.deleteWebhook
|
||||
|
||||
# Push Notifications
|
||||
"/user/pushDevice":
|
||||
spec:
|
||||
method: 'POST'
|
||||
description: 'Add a new push devices registration ID'
|
||||
parameters: [
|
||||
body '','New push registration { regId: "123123", type: "android"}','object'
|
||||
]
|
||||
action: user.addPushDevice
|
||||
|
||||
# ---------------------------------
|
||||
# Groups
|
||||
# ---------------------------------
|
||||
|
||||
@@ -87,7 +87,7 @@ module.exports.txnEmail = function(mailingInfoArray, emailType, variables, perso
|
||||
},
|
||||
{
|
||||
name: 'RECIPIENT_UNSUB_URL',
|
||||
content: baseUrl + '/unsubscribe?code=' + module.exports.encrypt(JSON.stringify({
|
||||
content: '/unsubscribe?code=' + module.exports.encrypt(JSON.stringify({
|
||||
_id: mailingInfo._id,
|
||||
email: mailingInfo.email
|
||||
}))
|
||||
@@ -113,7 +113,7 @@ module.exports.txnEmail = function(mailingInfoArray, emailType, variables, perso
|
||||
},
|
||||
{
|
||||
name: 'RECIPIENT_UNSUB_URL',
|
||||
content: baseUrl + '/unsubscribe?code=' + module.exports.encrypt(JSON.stringify({
|
||||
content: '/unsubscribe?code=' + module.exports.encrypt(JSON.stringify({
|
||||
_id: temporaryPersonalVariables[singlePersonalVariables.rcpt]._id,
|
||||
email: singlePersonalVariables.rcpt
|
||||
}))
|
||||
|
||||
Reference in New Issue
Block a user