diff --git a/migrations/20131102_restore_task_ids.js b/migrations/20131102_restore_task_ids.js
new file mode 100644
index 0000000000..260675fbf5
--- /dev/null
+++ b/migrations/20131102_restore_task_ids.js
@@ -0,0 +1,25 @@
+// mongo habitrpg ./node_modules/lodash/lodash.js ./migrations/20131028_task_subdocs_tags_invites.js
+
+db.challenges.find().forEach(function(chal){
+ _.each(chal.habits.concat(chal.dailys).concat(chal.todos).concat(chal.rewards), function(task){
+ task.id = task.id || task._id;
+ })
+ try {
+ db.challenges.update({_id:chal._id}, chal);
+ db.groups.update({_id:chal.group}, {$addToSet:{challenges:chal._id}})
+ } catch(e) {
+ print(e);
+ }
+});
+
+db.users.find().forEach(function(user){
+ _.each(user.habits.concat(user.dailys).concat(user.todos).concat(user.rewards), function(task){
+ task.id = task.id || task._id;
+ })
+ try {
+ db.users.update({_id:user._id}, user);
+ } catch(e) {
+ print(e);
+ }
+});
+
diff --git a/src/controllers/challenges.js b/src/controllers/challenges.js
index 6983e7cd76..eaf15b0bc9 100644
--- a/src/controllers/challenges.js
+++ b/src/controllers/challenges.js
@@ -123,54 +123,63 @@ api.getMember = function(req, res) {
// CREATE
api.create = function(req, res){
var user = res.locals.user;
- var waterfall = [];
+ var group, chal;
+
+ // First, make sure they've selected a legit group, and store it for later
+ var waterfall = [
+ function(cb){
+ Group.findById(req.body.group).exec(cb);
+ },
+ function(_group, cb){
+ if (!_group) return cb("Group." + req.body.group + " not found");
+ group = _group;
+ cb(null);
+ }
+ ];
+
+ // If they're adding a prize, do some validation
if (+req.body.prize < 0) return res.json(401, {err: 'Challenge prize must be >= 0'});
if (req.body.group=='habitrpg' && +req.body.prize < 1) return res.json(401, {err: 'Prize must be at least 1 Gem for public challenges.'});
if (+req.body.prize > 0) {
- waterfall = [
- function(cb){
- Group.findById(req.body.group).select('balance leader').exec(cb);
- },
- function(group, cb){
- if (!group) return cb("Group." + req.body.group + " not found");
- var groupBalance = ((group.balance && group.leader==user._id) ? group.balance : 0);
- if (req.body.prize > (user.balance*4 + groupBalance*4))
- return cb("Challenge.prize > (your gems + group balance). Purchase more gems or lower prize amount.s")
+ waterfall.push(function(cb){
+ var groupBalance = ((group.balance && group.leader==user._id) ? group.balance : 0);
+ if (req.body.prize > (user.balance*4 + groupBalance*4))
+ return cb("Challenge.prize > (your gems + group balance). Purchase more gems or lower prize amount.s")
- var net = req.body.prize/4; // I really should have stored user.balance as gems rather than dollars... stupid...
+ var net = req.body.prize/4; // I really should have stored user.balance as gems rather than dollars... stupid...
- // user is group leader, and group has balance. Subtract from that first, then take the rest from user
- if (groupBalance > 0) {
- group.balance -= net;
- if (group.balance < 0) {
- net = Math.abs(group.balance);
- group.balance = 0;
- }
+ // user is group leader, and group has balance. Subtract from that first, then take the rest from user
+ if (groupBalance > 0) {
+ group.balance -= net;
+ if (group.balance < 0) {
+ net = Math.abs(group.balance);
+ group.balance = 0;
}
- user.balance -= net;
- group.save(cb)
}
- ];
+ user.balance -= net;
+ cb(null)
+ });
}
+
waterfall = waterfall.concat([
- function() { // if we're dealing with prize above, arguemnts will be `group, numRows, cb` - else `cb`
- var cb = arguments[arguments.length-1];
- var challenge = new Challenge(req.body); // FIXME sanitize
- challenge.members.push(user._id);
- challenge.save(cb);
+ function(cb) { // if we're dealing with prize above, arguemnts will be `group, numRows, cb` - else `cb`
+ var chal = new Challenge(req.body); // FIXME sanitize
+ chal.members.push(user._id);
+ chal.save(cb)
},
- function(chal, num, cb) {
+ function(_chal, num, cb){
+ chal = _chal;
+ group.challenges.push(chal._id);
+ group.save(cb);
+ },
+ function(_group, num, cb) {
// Auto-join creator to challenge (see members.push above)
syncChalToUser(chal, user);
- user.save(function(err){
- if (err) return cb(err);
- cb(null, chal);
- });
+ user.save(cb);
}
]);
- async.waterfall(waterfall, function(err, chal){
+ async.waterfall(waterfall, function(err){
if (err) return res.json(500, {err:err});
- Group.update({_id:chal.group}, {$addToSet:{challenges:chal._id}}) // fixme error-check, and also better to do in middleware?
res.json(chal);
});
}
@@ -255,7 +264,8 @@ function closeChal(cid, broken, cb) {
function(users, cb2) {
var parallel = [];
_.each(users, function(user){
- _.find(user.tags, {id:cid}).challenge = undefined;
+ var tag = _.find(user.tags, {id:cid});
+ if (tag) tag.challenge = undefined;
_.each(user.tasks, function(task){
if (task.challenge && task.challenge.id == removed._id) {
_.merge(task.challenge, broken);
diff --git a/views/options/social/challenge-box.jade b/views/options/social/challenge-box.jade
new file mode 100644
index 0000000000..213e61b724
--- /dev/null
+++ b/views/options/social/challenge-box.jade
@@ -0,0 +1,16 @@
+// ------ Challenges -------
+.modal(style='position: relative;top: auto;left: auto;right: auto;margin: 0 auto 20px;z-index: 1;max-width: 100%;')
+ .modal-header
+ h3
+ | Challenges
+ a.pull-right(target='_blank', href='https://trello.com/card/challenges-individual-party-guild-public/50e5d3684fe3a7266b0036d6/58')
+ i.icon-question-sign
+ .modal-body
+ div(ng-if='group.challenges.length > 0')
+ table.table.table-striped
+ tr(ng-repeat='challenge in group.challenges')
+ td
+ a(ui-sref='options.social.challenges.detail({cid:challenge._id})') {{challenge.name}}
+ div(ng-if='group.challenges.length == 0')
+ p.
+ No challenges yet, visit Challenges to create one.
\ No newline at end of file
diff --git a/views/options/social/group.jade b/views/options/social/group.jade
index 189d39a4fa..28a71938e6 100644
--- a/views/options/social/group.jade
+++ b/views/options/social/group.jade
@@ -47,24 +47,7 @@ a.pull-right.gem-wallet(popover-trigger='mouseenter', popover-title='Guild Bank'
li(ng-repeat='website in group.websites')
a(target='_blank', ng-href='{{website}}') {{website}}
- // ------ Challenges -------
- .modal(style='position: relative;top: auto;left: auto;right: auto;margin: 0 auto 20px;z-index: 1;max-width: 100%;')
- .modal-header
- h3
- | Challenges
- a.pull-right(target='_blank', href='https://trello.com/card/challenges-individual-party-guild-public/50e5d3684fe3a7266b0036d6/58')
- i.icon-question-sign
- .modal-body
- div(ng-if='group.challenges.length > 0')
- table.table.table-striped
- tr(ng-repeat='challenge in group.challenges')
- td
- a(ui-sref='options.social.challenges.detail({cid:challenge._id})') {{challenge.name}}
- p.
- Visit the Challenges for more information.
- div(ng-if='group.challenges.length == 0')
- p.
- No challenges yet, visit the Challenges tab to create one.
+ include ./challenge-box
// ------ Members -------
.modal(style='position: relative;top: auto;left: auto;right: auto;margin: 0 auto 20px;z-index: 1;max-width: 100%;')
diff --git a/views/options/social/tavern.jade b/views/options/social/tavern.jade
index 54e21ce681..f4ba422d0c 100644
--- a/views/options/social/tavern.jade
+++ b/views/options/social/tavern.jade
@@ -42,6 +42,8 @@
h4
a(target='_blank', href='http://community.habitrpg.com/forum') Community Forum
+ include ./challenge-box
+
.span8(ng-controller='ChatCtrl')
h3 Tavern Talk
.row-fluid