'use strict'; var async = require('async'); var db = require('../database'); var plugins = require('../plugins'); var rewards = module.exports; rewards.checkConditionAndRewardUser = function (uid, condition, method, callback) { callback = callback || function () {}; async.waterfall([ function (next) { isConditionActive(condition, next); }, function (isActive, next) { if (!isActive) { return callback(); } getIDsByCondition(condition, next); }, function (ids, next) { getRewardDataByIDs(ids, next); }, function (rewards, next) { filterCompletedRewards(uid, rewards, next); }, function (rewards, next) { if (!rewards || !rewards.length) { return callback(); } async.filter(rewards, function (reward, next) { if (!reward) { return next(null, false); } checkCondition(reward, method, next); }, function (err, eligible) { if (err || !eligible) { return next(false); } giveRewards(uid, eligible, next); }); }, ], callback); }; function isConditionActive(condition, callback) { db.isSetMember('conditions:active', condition, callback); } function getIDsByCondition(condition, callback) { db.getSetMembers('condition:' + condition + ':rewards', callback); } function filterCompletedRewards(uid, rewards, callback) { async.waterfall([ function (next) { db.getSortedSetRangeByScoreWithScores('uid:' + uid + ':rewards', 0, -1, 1, '+inf', next); }, function (data, next) { var userRewards = {}; data.forEach(function (obj) { userRewards[obj.value] = parseInt(obj.score, 10); }); rewards = rewards.filter(function (reward) { if (!reward) { return false; } var claimable = parseInt(reward.claimable, 10); return claimable === 0 || (!userRewards[reward.id] || userRewards[reward.id] < reward.claimable); }); next(null, rewards); }, ], callback); } function getRewardDataByIDs(ids, callback) { db.getObjects(ids.map(function (id) { return 'rewards:id:' + id; }), callback); } function getRewardsByRewardData(rewards, callback) { db.getObjects(rewards.map(function (reward) { return 'rewards:id:' + reward.id + ':rewards'; }), callback); } function checkCondition(reward, method, callback) { async.waterfall([ function (next) { method(next); }, function (value, next) { plugins.fireHook('filter:rewards.checkConditional:' + reward.conditional, { left: value, right: reward.value }, next); }, function (bool, next) { next(null, bool); }, ], callback); } function giveRewards(uid, rewards, callback) { async.waterfall([ function (next) { getRewardsByRewardData(rewards, next); }, function (rewardData, next) { async.each(rewards, function (reward, next) { plugins.fireHook('action:rewards.award:' + reward.rid, { uid: uid, reward: rewardData[rewards.indexOf(reward)] }); db.sortedSetIncrBy('uid:' + uid + ':rewards', 1, reward.id, next); }, next); }, ], callback); }