Merge branch 'develop' into srrvnn-develop
This commit is contained in:
@@ -16,19 +16,15 @@ var isProd = nconf.get('NODE_ENV') === 'production';
|
||||
|
||||
var api = module.exports;
|
||||
|
||||
var NO_TOKEN_OR_UID = { err: "You must include a token and uid (user id) in your request"};
|
||||
var NO_USER_FOUND = {err: "No user found."};
|
||||
var NO_SESSION_FOUND = { err: "You must be logged in." };
|
||||
var NO_TOKEN_OR_UID = { err: shared.i18n.t('messageAuthMustIncludeTokens') };
|
||||
var NO_USER_FOUND = {err: shared.i18n.t('messageAuthNoUserFound') };
|
||||
var NO_SESSION_FOUND = { err: shared.i18n.t('messageAuthMustBeLoggedIn') };
|
||||
var accountSuspended = function(uuid){
|
||||
return {
|
||||
err: 'Account has been suspended, please contact leslie@habitica.com with your UUID ('+uuid+') for assistance.',
|
||||
code: 'ACCOUNT_SUSPENDED'
|
||||
};
|
||||
}
|
||||
// Allow case-insensitive regex searching for Mongo queries. See http://stackoverflow.com/a/3561711/362790
|
||||
var RegexEscape = function(s){
|
||||
return new RegExp('^' + s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&') + '$', 'i');
|
||||
}
|
||||
|
||||
api.auth = function(req, res, next) {
|
||||
var uid = req.headers['x-api-user'];
|
||||
@@ -67,35 +63,42 @@ api.authWithUrl = function(req, res, next) {
|
||||
}
|
||||
|
||||
api.registerUser = function(req, res, next) {
|
||||
var regEmail = RegexEscape(req.body.email),
|
||||
regUname = RegexEscape(req.body.username);
|
||||
var email = req.body.email && req.body.email.toLowerCase();
|
||||
var username = req.body.username;
|
||||
// Get the lowercase version of username to check that we do not have duplicates
|
||||
// So we can search for it in the database and then reject the choosen username if 1 or more results are found
|
||||
var lowerCaseUsername = username && username.toLowerCase();
|
||||
|
||||
async.auto({
|
||||
validate: function(cb) {
|
||||
if (!(req.body.username && req.body.password && req.body.email))
|
||||
return cb({code:401, err: ":username, :email, :password, :confirmPassword required"});
|
||||
if (!(username && req.body.password && email))
|
||||
return cb({code:401, err: shared.i18n.t('messageAuthCredentialsRequired')});
|
||||
if (req.body.password !== req.body.confirmPassword)
|
||||
return cb({code:401, err: ":password and :confirmPassword don't match"});
|
||||
if (!validator.isEmail(req.body.email))
|
||||
return cb({code:401, err: shared.i18n.t('messageAuthPasswordMustMatch')});
|
||||
if (!validator.isEmail(email))
|
||||
return cb({code:401, err: ":email invalid"});
|
||||
cb();
|
||||
},
|
||||
findReg: function(cb) {
|
||||
User.findOne({$or:[{'auth.local.email': regEmail}, {'auth.local.username': regUname}]}, {'auth.local':1}, cb);
|
||||
// Search for duplicates using lowercase version of username
|
||||
User.findOne({$or:[{'auth.local.email': email}, {'auth.local.lowerCaseUsername': lowerCaseUsername}]}, {'auth.local':1}, cb);
|
||||
},
|
||||
findFacebook: function(cb){
|
||||
User.findOne({_id: req.headers['x-api-user'], apiToken: req.headers['x-api-key']}, {auth:1}, cb);
|
||||
},
|
||||
register: ['validate', 'findReg', 'findFacebook', function(cb, data) {
|
||||
if (data.findReg) {
|
||||
if (regEmail.test(data.findReg.auth.local.email)) return cb({code:401, err:"Email already taken"});
|
||||
if (regUname.test(data.findReg.auth.local.username)) return cb({code:401, err:"Username already taken"});
|
||||
if (email === data.findReg.auth.local.email) return cb({code:401, err:"Email already taken"});
|
||||
// Check that the lowercase username isn't already used
|
||||
if (lowerCaseUsername === data.findReg.auth.local.lowerCaseUsername) return cb({code:401, err: shared.i18n.t('messageAuthUsernameTaken')});
|
||||
}
|
||||
var salt = utils.makeSalt();
|
||||
var newUser = {
|
||||
auth: {
|
||||
local: {
|
||||
username: req.body.username,
|
||||
email: req.body.email,
|
||||
username: username,
|
||||
lowerCaseUsername: lowerCaseUsername, // Store the lowercase version of the username
|
||||
email: email, // Store email as lowercase
|
||||
salt: salt,
|
||||
hashed_password: utils.encryptPassword(req.body.password, salt)
|
||||
},
|
||||
@@ -115,12 +118,14 @@ api.registerUser = function(req, res, next) {
|
||||
var analyticsData = {
|
||||
category: 'acquisition',
|
||||
type: 'local',
|
||||
gaLabel: 'local'
|
||||
gaLabel: 'local',
|
||||
uuid: user._id,
|
||||
};
|
||||
analytics.track('register', analyticsData)
|
||||
|
||||
user.save(function(err, savedUser){
|
||||
// Clean previous email preferences
|
||||
// TODO when emails added to EmailUnsubcription they should use lowercase version
|
||||
EmailUnsubscription.remove({email: savedUser.auth.local.email}, function(){
|
||||
utils.txnEmail(savedUser, 'welcome');
|
||||
});
|
||||
@@ -143,7 +148,10 @@ api.loginLocal = function(req, res, next) {
|
||||
var username = req.body.username;
|
||||
var password = req.body.password;
|
||||
if (!(username && password)) return res.json(401, {err:'Missing :username or :password in request body, please provide both'});
|
||||
var login = validator.isEmail(username) ? {'auth.local.email':username} : {'auth.local.username':username};
|
||||
var login = validator.isEmail(username) ?
|
||||
{'auth.local.email':username.toLowerCase()} : // Emails are all lowercase
|
||||
{'auth.local.username':username}; // Use the username as the user typed it
|
||||
|
||||
User.findOne(login, {auth:1}, function(err, user){
|
||||
if (err) return next(err);
|
||||
if (!user) return res.json(401, {err:"Uh-oh - your username or password is incorrect.\n- Make sure your username or email is typed correctly.\n- You may have signed up with Facebook, not email. Double-check by trying Facebook login.\n- If you forgot your password, click \"Forgot Password\"."});
|
||||
@@ -205,7 +213,8 @@ api.loginSocial = function(req, res, next) {
|
||||
var analyticsData = {
|
||||
category: 'acquisition',
|
||||
type: network,
|
||||
gaLabel: network
|
||||
gaLabel: network,
|
||||
uuid: user._id,
|
||||
};
|
||||
analytics.track('register', analyticsData)
|
||||
}]
|
||||
@@ -233,12 +242,14 @@ api.deleteSocial = function(req,res,next){
|
||||
}
|
||||
|
||||
api.resetPassword = function(req, res, next){
|
||||
var email = req.body.email,
|
||||
var email = req.body.email && req.body.email.toLowerCase(), // Emails are all lowercase
|
||||
salt = utils.makeSalt(),
|
||||
newPassword = utils.makeSalt(), // use a salt as the new password too (they'll change it later)
|
||||
hashed_password = utils.encryptPassword(newPassword, salt);
|
||||
|
||||
User.findOne({'auth.local.email': RegexEscape(email)}, function(err, user){
|
||||
if(!email) return res.json(400, {err: "Email not provided"});
|
||||
|
||||
User.findOne({'auth.local.email': email}, function(err, user){
|
||||
if (err) return next(err);
|
||||
if (!user) return res.send(401, {err:"Sorry, we can't find a user registered with email " + email + "\n- Make sure your email address is typed correctly.\n- You may have signed up with Facebook, not email. Double-check by trying Facebook login."});
|
||||
user.auth.local.salt = salt;
|
||||
@@ -266,15 +277,22 @@ var invalidPassword = function(user, password){
|
||||
}
|
||||
|
||||
api.changeUsername = function(req, res, next) {
|
||||
var user = res.locals.user;
|
||||
var username = req.body.username;
|
||||
var lowerCaseUsername = username && username.toLowerCase(); // we search for the lowercased version to intercept duplicates
|
||||
|
||||
if(!username) return res.json(400, {err: "Username not provided"});
|
||||
async.waterfall([
|
||||
function(cb){
|
||||
User.findOne({'auth.local.username': RegexEscape(req.body.username)}, {auth:1}, cb);
|
||||
User.findOne({'auth.local.lowerCaseUsername': lowerCaseUsername}, {auth:1}, cb);
|
||||
},
|
||||
function(found, cb){
|
||||
if (found) return cb({code:401, err: "Username already taken"});
|
||||
if (invalidPassword(res.locals.user, req.body.password)) return cb(invalidPassword(res.locals.user, req.body.password));
|
||||
res.locals.user.auth.local.username = req.body.username;
|
||||
res.locals.user.save(cb);
|
||||
if (invalidPassword(user, req.body.password)) return cb(invalidPassword(user, req.body.password));
|
||||
user.auth.local.username = username;
|
||||
user.auth.local.lowerCaseUsername = lowerCaseUsername;
|
||||
|
||||
user.save(cb);
|
||||
}
|
||||
], function(err){
|
||||
if (err) return err.code ? res.json(err.code, err) : next(err);
|
||||
@@ -283,14 +301,17 @@ api.changeUsername = function(req, res, next) {
|
||||
}
|
||||
|
||||
api.changeEmail = function(req, res, next){
|
||||
var email = req.body.email && req.body.email.toLowerCase(); // emails are all lowercase
|
||||
if(!email) return res.json(400, {err: "Email not provided"});
|
||||
|
||||
async.waterfall([
|
||||
function(cb){
|
||||
User.findOne({'auth.local.email': RegexEscape(req.body.email)}, {auth:1}, cb);
|
||||
User.findOne({'auth.local.email': email}, {auth:1}, cb);
|
||||
},
|
||||
function(found, cb){
|
||||
if(found) return cb({code:401, err: "Email already taken"});
|
||||
if(found) return cb({code:401, err: shared.i18n.t('messageAuthEmailTaken')});
|
||||
if (invalidPassword(res.locals.user, req.body.password)) return cb(invalidPassword(res.locals.user, req.body.password));
|
||||
res.locals.user.auth.local.email = req.body.email;
|
||||
res.locals.user.auth.local.email = email;
|
||||
res.locals.user.save(cb);
|
||||
}
|
||||
], function(err){
|
||||
@@ -333,7 +354,7 @@ api.getFirebaseToken = function(req, res, next) {
|
||||
.createToken({
|
||||
uid: user._id,
|
||||
isHabiticaUser: true
|
||||
}, {
|
||||
}, {
|
||||
expires: expires
|
||||
});
|
||||
|
||||
|
||||
@@ -230,7 +230,7 @@ api.update = function(req, res, next){
|
||||
// before-save / after-save comparison to determine if we need to sync to users
|
||||
before = _before;
|
||||
var attrs = _.pick(req.body, 'name shortName description habits dailys todos rewards date'.split(' '));
|
||||
Challenge.findByIdAndUpdate(cid, {$set:attrs}, cb);
|
||||
Challenge.findByIdAndUpdate(cid, {$set:attrs}, {new: true}, cb);
|
||||
},
|
||||
function(saved, cb) {
|
||||
|
||||
@@ -271,7 +271,7 @@ function closeChal(cid, broken, cb) {
|
||||
function(_removed, cb2) {
|
||||
removed = _removed;
|
||||
var pull = {'$pull':{}}; pull['$pull'][_removed._id] = 1;
|
||||
Group.findByIdAndUpdate(_removed.group, pull);
|
||||
Group.findByIdAndUpdate(_removed.group, {new: true}, pull);
|
||||
User.find({_id:{$in: removed.members}}, cb2);
|
||||
},
|
||||
function(users, cb2) {
|
||||
@@ -297,7 +297,7 @@ function closeChal(cid, broken, cb) {
|
||||
/**
|
||||
* Delete & close
|
||||
*/
|
||||
api['delete'] = function(req, res, next){
|
||||
api.delete = function(req, res, next){
|
||||
var user = res.locals.user;
|
||||
var cid = req.params.cid;
|
||||
|
||||
@@ -370,7 +370,7 @@ api.join = function(req, res, next){
|
||||
|
||||
async.waterfall([
|
||||
function(cb) {
|
||||
Challenge.findByIdAndUpdate(cid, {$addToSet:{members:user._id}}, cb);
|
||||
Challenge.findByIdAndUpdate(cid, {$addToSet:{members:user._id}}, {new: true}, cb);
|
||||
},
|
||||
function(chal, cb) {
|
||||
|
||||
@@ -403,7 +403,7 @@ api.leave = function(req, res, next){
|
||||
|
||||
async.waterfall([
|
||||
function(cb){
|
||||
Challenge.findByIdAndUpdate(cid, {$pull:{members:user._id}}, cb);
|
||||
Challenge.findByIdAndUpdate(cid, {$pull:{members:user._id}}, {new: true}, cb);
|
||||
},
|
||||
function(chal, cb){
|
||||
|
||||
|
||||
@@ -143,7 +143,7 @@ api.get = function(req, res, next) {
|
||||
q.exec(function(err, group){
|
||||
if (err) return next(err);
|
||||
if(!group){
|
||||
if(gid !== 'party') return res.json(404,{err: "Group not found or you don't have access."});
|
||||
if(gid !== 'party') return res.json(404,{err: shared.i18n.t('messageGroupNotFound')});
|
||||
|
||||
// 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
|
||||
@@ -188,7 +188,7 @@ api.create = function(req, res, next) {
|
||||
group.leader = user._id;
|
||||
|
||||
if(group.type === 'guild'){
|
||||
if(user.balance < 1) return res.json(401, {err: 'Not enough gems!'});
|
||||
if(user.balance < 1) return res.json(401, {err: shared.i18n.t('messageInsufficientGems')});
|
||||
|
||||
group.balance = 1;
|
||||
user.balance--;
|
||||
@@ -213,7 +213,7 @@ api.create = function(req, res, next) {
|
||||
Group.findOne({type:'party',members:{$in:[user._id]}},cb);
|
||||
},
|
||||
function(found, cb){
|
||||
if (found) return cb('Already in a party, try refreshing.');
|
||||
if (found) return cb(shared.i18n.t('messageGroupAlreadyInParty'));
|
||||
group.save(cb);
|
||||
},
|
||||
function(saved, count, cb){
|
||||
@@ -222,7 +222,7 @@ api.create = function(req, res, next) {
|
||||
saved.populate('members', nameFields, cb);
|
||||
}
|
||||
], function(err, populated){
|
||||
if (err == 'Already in a party, try refreshing.') return res.json(400,{err:err});
|
||||
if (err === shared.i18n.t('messageGroupAlreadyInParty')) return res.json(400,{err:err});
|
||||
if (err) return next(err);
|
||||
group = user = null;
|
||||
return res.json(populated);
|
||||
@@ -235,7 +235,7 @@ api.update = function(req, res, next) {
|
||||
var user = res.locals.user;
|
||||
|
||||
if(group.leader !== user._id)
|
||||
return res.json(401, {err: "Only the group leader can update the group!"});
|
||||
return res.json(401, {err: shared.i18n.t('messageGroupOnlyLeaderCanUpdate')});
|
||||
|
||||
'name description logo logo leaderMessage leader leaderOnly'.split(' ').forEach(function(attr){
|
||||
group[attr] = req.body[attr];
|
||||
@@ -255,7 +255,7 @@ api.attachGroup = function(req, res, next) {
|
||||
var q = (gid == 'party') ? Group.findOne({type: 'party', members: {'$in': [res.locals.user._id]}}) : Group.findById(gid);
|
||||
q.exec(function(err, group){
|
||||
if(err) return next(err);
|
||||
if(!group) return res.json(404, {err: "Group not found"});
|
||||
if(!group) return res.json(404, {err: shared.i18n.t('messageGroupNotFound')});
|
||||
res.locals.group = group;
|
||||
next();
|
||||
});
|
||||
@@ -274,7 +274,7 @@ api.getChat = 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."});
|
||||
if (!group && gid!=='party') return res.json(404,{err: shared.i18n.t('messageGroupNotFound')});
|
||||
//Remove flagged messages if the user is not mod
|
||||
if (!user.contributor.admin) {
|
||||
group.chat = _.filter(group.chat, function(message) { return !message.flagCount || message.flagCount < 2; });
|
||||
@@ -289,7 +289,7 @@ api.getChat = function(req, res, next) {
|
||||
*/
|
||||
api.postChat = function(req, res, next) {
|
||||
if(!req.query.message) {
|
||||
return res.json(400,{err:'You cannot send a blank message'});
|
||||
return res.json(400,{err: shared.i18n.t('messageGroupChatBlankMessage')});
|
||||
} else {
|
||||
var user = res.locals.user
|
||||
var group = res.locals.group;
|
||||
@@ -337,15 +337,15 @@ api.flagChatMessage = function(req, res, next){
|
||||
var group = res.locals.group;
|
||||
var message = _.find(group.chat, {id: req.params.mid});
|
||||
|
||||
if(!message) return res.json(404, {err: "Message not found!"});
|
||||
if(message.uuid == user._id) return res.json(401, {err: "Can't report your own message."});
|
||||
if(!message) return res.json(404, {err: shared.i18n.t('messageGroupChatNotFound')});
|
||||
if(message.uuid == user._id) return res.json(401, {err: shared.i18n.t('messageGroupChatFlagOwnMessage')});
|
||||
|
||||
User.findOne({_id: message.uuid}, {auth: 1}, function(err, author){
|
||||
if(err) return next(err);
|
||||
|
||||
// Log user ids that have flagged the message
|
||||
if(!message.flags) message.flags = {};
|
||||
if(message.flags[user._id] && !user.contributor.admin) return res.json(401, {err: "You have already reported this message"});
|
||||
if(message.flags[user._id] && !user.contributor.admin) return res.json(401, {err: shared.i18n.t('messageGroupChatFlagAlreadyReported')});
|
||||
message.flags[user._id] = true;
|
||||
|
||||
// Log total number of flags (publicly viewable)
|
||||
@@ -402,7 +402,7 @@ api.clearFlagCount = function(req, res, next){
|
||||
var group = res.locals.group;
|
||||
var message = _.find(group.chat, {id: req.params.mid});
|
||||
|
||||
if(!message) return res.json(404, {err: "Message not found!"});
|
||||
if(!message) return res.json(404, {err: shared.i18n.t('messageGroupChatNotFound')});
|
||||
|
||||
if(user.contributor.admin){
|
||||
message.flagCount = 0;
|
||||
@@ -413,7 +413,7 @@ api.clearFlagCount = function(req, res, next){
|
||||
return res.send(204);
|
||||
});
|
||||
}else{
|
||||
return res.json(401, {err: "Only an admin can clear the flag count!"})
|
||||
return res.json(401, {err: shared.i18n.t('messageGroupChatAdminClearFlagCount')})
|
||||
}
|
||||
|
||||
}
|
||||
@@ -433,8 +433,8 @@ api.likeChatMessage = function(req, res, next) {
|
||||
var user = res.locals.user;
|
||||
var group = res.locals.group;
|
||||
var message = _.find(group.chat, {id: req.params.mid});
|
||||
if (!message) return res.json(404, {err: "Message not found!"});
|
||||
if (message.uuid == user._id) return res.json(401, {err: "Can't like your own message. Don't be that person."});
|
||||
if (!message) return res.json(404, {err: shared.i18n.t('messageGroupChatNotFound')});
|
||||
if (message.uuid == user._id) return res.json(401, {err: shared.i18n.t('messageGroupChatLikeOwnMessage')});
|
||||
if (!message.likes) message.likes = {};
|
||||
if (message.likes[user._id]) {
|
||||
delete message.likes[user._id];
|
||||
@@ -478,7 +478,7 @@ api.join = function(req, res, next) {
|
||||
}
|
||||
}
|
||||
|
||||
if(!isUserInvited) return res.json(401, {err: "Can't join a group you're not invited to."});
|
||||
if(!isUserInvited) return res.json(401, {err: shared.i18n.t('messageGroupRequiresInvite')});
|
||||
|
||||
if (!_.contains(group.members, user._id)){
|
||||
if (group.members.length === 0) {
|
||||
@@ -529,6 +529,7 @@ api.leave = function(req, res, next) {
|
||||
group.leave(user, keep, function(err){
|
||||
if (err) return next(err);
|
||||
user = group = keep = null;
|
||||
|
||||
return res.send(204);
|
||||
});
|
||||
};
|
||||
@@ -691,7 +692,7 @@ api.invite = function(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"});
|
||||
return res.json(400, {err: "Can only invite by email or uuid"});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -920,7 +921,8 @@ api.questAccept = function(req, res, next) {
|
||||
owner: true,
|
||||
response: 'accept',
|
||||
gaLabel: 'accept',
|
||||
questName: key
|
||||
questName: key,
|
||||
uuid: user._id,
|
||||
};
|
||||
analytics.track('quest',analyticsData);
|
||||
group.quest.members[m] = true;
|
||||
@@ -966,7 +968,8 @@ api.questAccept = function(req, res, next) {
|
||||
owner: false,
|
||||
response: 'accept',
|
||||
gaLabel: 'accept',
|
||||
questName: group.quest.key
|
||||
questName: group.quest.key,
|
||||
uuid: user._id,
|
||||
};
|
||||
analytics.track('quest',analyticsData);
|
||||
group.quest.members[user._id] = true;
|
||||
@@ -985,7 +988,8 @@ api.questReject = function(req, res, next) {
|
||||
owner: false,
|
||||
response: 'reject',
|
||||
gaLabel: 'reject',
|
||||
questName: group.quest.key
|
||||
questName: group.quest.key,
|
||||
uuid: user._id,
|
||||
};
|
||||
analytics.track('quest',analyticsData);
|
||||
group.quest.members[user._id] = false;
|
||||
|
||||
@@ -101,9 +101,27 @@ exports.iosVerify = function(req, res, next) {
|
||||
if (iap.isValidated(appleRes)) {
|
||||
var purchaseDataList = iap.getPurchaseData(appleRes);
|
||||
if (purchaseDataList.length > 0) {
|
||||
if (purchaseDataList[0].productId === 'com.habitrpg.ios.Habitica.20gems') {
|
||||
//Correct receipt
|
||||
payments.buyGems({user:user, paymentMethod:'IAP AppleStore'});
|
||||
var correctReceipt = true;
|
||||
for (var index in purchaseDataList) {
|
||||
switch (purchaseDataList[index].productId) {
|
||||
case 'com.habitrpg.ios.Habitica.4gems':
|
||||
payments.buyGems({user:user, paymentMethod:'IAP AppleStore', amount: 1});
|
||||
break;
|
||||
case 'com.habitrpg.ios.Habitica.8gems':
|
||||
payments.buyGems({user:user, paymentMethod:'IAP AppleStore', amount: 2});
|
||||
break;
|
||||
case 'com.habitrpg.ios.Habitica.20gems':
|
||||
case 'com.habitrpg.ios.Habitica.21gems':
|
||||
payments.buyGems({user:user, paymentMethod:'IAP AppleStore', amount: 5.25});
|
||||
break;
|
||||
case 'com.habitrpg.ios.Habitica.42gems':
|
||||
payments.buyGems({user:user, paymentMethod:'IAP AppleStore', amount: 10.5});
|
||||
break;
|
||||
default:
|
||||
correctReceipt = false;
|
||||
}
|
||||
}
|
||||
if (correctReceipt) {
|
||||
var resObj = {
|
||||
ok: true,
|
||||
data: appleRes
|
||||
|
||||
@@ -137,7 +137,8 @@ exports.cancelSubscription = function(data, cb) {
|
||||
}
|
||||
|
||||
exports.buyGems = function(data, cb) {
|
||||
var amt = data.gift ? data.gift.gems.amount/4 : 5;
|
||||
var amt = data.amount || 5;
|
||||
amt = data.gift ? data.gift.gems.amount/4 : amt;
|
||||
(data.gift ? data.gift.member : data.user).balance += amt;
|
||||
data.user.purchased.txnCount++;
|
||||
if(isProduction) {
|
||||
|
||||
@@ -13,14 +13,14 @@ var gcm = gcmApiKey ? pushNotify.gcm({
|
||||
|
||||
if(gcm){
|
||||
gcm.on('transmitted', function (result, message, registrationId) {
|
||||
console.info("transmitted", result, message, registrationId);
|
||||
//console.info("transmitted", result, message, registrationId);
|
||||
});
|
||||
|
||||
gcm.on('transmissionError', function (error, message, registrationId) {
|
||||
console.info("transmissionError", error, message, registrationId);
|
||||
//console.info("transmissionError", error, message, registrationId);
|
||||
});
|
||||
gcm.on('updated', function (result, registrationId) {
|
||||
console.info("updated", result, registrationId);
|
||||
//console.info("updated", result, registrationId);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -13,9 +13,9 @@ api.unsubscribe = function(req, res, next){
|
||||
if(data._id){
|
||||
User.update({_id: data._id}, {
|
||||
$set: {'preferences.emailNotifications.unsubscribeFromAll': true}
|
||||
}, {multi: false}, function(err, nAffected){
|
||||
}, {multi: false}, function(err, updateRes){
|
||||
if(err) return next(err);
|
||||
if(nAffected !== 1) return res.json(404, {err: 'User not found'});
|
||||
if(updateRes !== 1) return res.json(404, {err: 'User not found'});
|
||||
|
||||
res.send('<h1>' + i18n.t('unsubscribedSuccessfully', null, req.language) + '</h1>' + i18n.t('unsubscribedTextUsers', null, req.language));
|
||||
});
|
||||
|
||||
@@ -164,7 +164,7 @@ api.getTasks = function(req, res, next) {
|
||||
*/
|
||||
api.getTask = function(req, res, next) {
|
||||
var task = findTask(req,res);
|
||||
if (!task) return res.json(404, {err: "No task found."});
|
||||
if (!task) return res.json(404, {err: shared.i18n.t('messageTaskNotFound')});
|
||||
return res.json(200, task);
|
||||
};
|
||||
|
||||
@@ -298,10 +298,9 @@ acceptablePUTPaths = _.reduce(require('./../models/user').schema.paths, function
|
||||
return m;
|
||||
}, {})
|
||||
|
||||
//// Uncomment this if we we want to disable GP-restoring (eg, holiday events)
|
||||
//_.each('stats.gp'.split(' '), function(removePath){
|
||||
// delete acceptablePUTPaths[removePath];
|
||||
//})
|
||||
_.each('stats.class'.split(' '), function(removePath){
|
||||
delete acceptablePUTPaths[removePath];
|
||||
})
|
||||
|
||||
/**
|
||||
* Update user
|
||||
@@ -318,7 +317,7 @@ api.update = function(req, res, next) {
|
||||
if (acceptablePUTPaths[k])
|
||||
user.fns.dotSet(k, v);
|
||||
else
|
||||
errors.push("path `" + k + "` was not saved, as it's a protected path. See https://github.com/HabitRPG/habitrpg/blob/develop/API.md for PUT /api/v2/user.");
|
||||
errors.push(shared.i18n.t('messageUserOperationProtected', { operation: k }));
|
||||
return true;
|
||||
});
|
||||
user.save(function(err) {
|
||||
@@ -365,7 +364,7 @@ api.cron = function(req, res, next) {
|
||||
// api.reroll // Shared.ops
|
||||
// api.reset // Shared.ops
|
||||
|
||||
api['delete'] = function(req, res, next) {
|
||||
api.delete = function(req, res, next) {
|
||||
var user = res.locals.user;
|
||||
var plan = user.purchased.plan;
|
||||
|
||||
@@ -397,38 +396,32 @@ api['delete'] = function(req, res, next) {
|
||||
|
||||
/*
|
||||
------------------------------------------------------------------------
|
||||
Gems
|
||||
Development Only Operations
|
||||
------------------------------------------------------------------------
|
||||
*/
|
||||
if (nconf.get('NODE_ENV') === 'development') {
|
||||
|
||||
// api.unlock // see Shared.ops
|
||||
api.addTenGems = function(req, res, next) {
|
||||
var user = res.locals.user;
|
||||
|
||||
api.addTenGems = function(req, res, next) {
|
||||
var user = res.locals.user;
|
||||
user.balance += 2.5;
|
||||
user.save(function(err){
|
||||
if (err) return next(err);
|
||||
res.send(204);
|
||||
})
|
||||
}
|
||||
user.balance += 2.5;
|
||||
|
||||
/*
|
||||
------------------------------------------------------------------------
|
||||
Hourglass
|
||||
------------------------------------------------------------------------
|
||||
*/
|
||||
user.save(function(err){
|
||||
if (err) return next(err);
|
||||
res.send(204);
|
||||
});
|
||||
};
|
||||
|
||||
// api.unlock // see Shared.ops
|
||||
api.addHourglass = function(req, res, next) {
|
||||
var user = res.locals.user;
|
||||
|
||||
api.addHourglass = function(req, res, next) {
|
||||
var user = res.locals.user;
|
||||
user.purchased.plan.consecutive.trinkets += 1;
|
||||
|
||||
user.purchased.plan.consecutive.trinkets += 1;
|
||||
|
||||
user.save(function(err){
|
||||
if (err) return next(err);
|
||||
res.send(204);
|
||||
})
|
||||
user.save(function(err){
|
||||
if (err) return next(err);
|
||||
res.send(204);
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -607,6 +600,7 @@ api.batchUpdate = function(req, res, next) {
|
||||
return cb(code+": "+ (data.message ? data.message : data.err ? data.err : JSON.stringify(data)));
|
||||
return cb();
|
||||
};
|
||||
if(!api[_req.op]) { return cb(shared.i18n.t('messageUserOperationNotFound', { operation: _req.op })); }
|
||||
api[_req.op](_req, res, cb);
|
||||
});
|
||||
})
|
||||
@@ -635,9 +629,7 @@ api.batchUpdate = function(req, res, next) {
|
||||
// Fetch full user object
|
||||
} else if (response.wasModified){
|
||||
// Preen 3-day past-completed To-Dos from Angular & mobile app
|
||||
response.todos = _.where(response.todos, function(t) {
|
||||
return !t.completed || (t.challenge && t.challenge.id) || moment(t.dateCompleted).isAfter(moment().subtract({days:3}));
|
||||
});
|
||||
response.todos = shared.preenTodos(response.todos);
|
||||
res.json(200, response);
|
||||
|
||||
// return only the version number
|
||||
|
||||
Reference in New Issue
Block a user