diff --git a/src/controllers/challenges.js b/src/controllers/challenges.js
index f34c55f6de..0d3e78008e 100644
--- a/src/controllers/challenges.js
+++ b/src/controllers/challenges.js
@@ -206,32 +206,71 @@ api.update = function(req, res){
})
}
-// DELETE
-api['delete'] = function(req, res){
+/**
+ * Called by either delete() or selectWinner(). Will delete the challenge and set the "broken" property on all users' subscribed tasks
+ * @param {cid} the challenge id
+ * @param {broken} the object representing the broken status of the challenge. Eg:
+ * {broken: 'CHALLENGE_DELETED', id: CHALLENGE_ID}
+ * {broken: 'CHALLENGE_CLOSED', id: CHALLENGE_ID, winner: USER_NAME}
+ */
+function closeChal(cid, broken, cb) {
var removed;
async.waterfall([
- function(cb){
- Challenge.findOneAndRemove({_id:req.params.cid}, cb)
+ function(cb2){
+ Challenge.findOneAndRemove({_id:cid}, cb2)
},
- function(_removed, cb) {
+ function(_removed, cb2) {
removed = _removed;
- User.find({_id:{$in: removed.members}}, cb);
+ User.find({_id:{$in: removed.members}}, cb2);
},
- function(users, cb) {
+ function(users, cb2) {
var parallel = [];
_.each(users, function(user){
_.each(user.tasks, function(task){
if (task.challenge && task.challenge.id == removed._id) {
- task.challenge.broken = 'CHALLENGE_DELETED';
+ _.mege(task.challenge, broken);
}
})
- parallel.push(function(cb2){
- user.save(cb2);
+ parallel.push(function(cb3){
+ user.save(cb3);
})
})
- async.parallel(parallel, cb);
+ async.parallel(parallel, cb2);
}
- ], function(err){
+ ], cb);
+}
+
+// DELETE
+api['delete'] = function(req, res){
+ closeChal(req.params.cid, {broken: 'CHALLENGE_DELETED'}, function(err){
+ if (err) return res.json(500, {err: err});
+ res.send(200);
+ })
+}
+
+api.selectWinner = function(req, res) {
+ if (!req.query.uid) return res.json(401, {err: 'Must select a winner'});
+ var chal;
+ async.waterfall([
+ function(cb){
+ Challenge.findById(req.params.cid, cb);
+ },
+ function(_chal, cb){
+ if (!_chal) return cb('Challenge ' + req.params.cid + ' not found.');
+ chal = _chal;
+ User.findById(req.query.uid, cb)
+ },
+ function(winner, cb){
+ if (!winner) return cb('Winner ' + req.query.uid + ' not found.');
+ _.defaults(winner.achievements, {challenges: []});
+ winner.achievements.challenges.push(chal.name);
+ winner.balance += chal.prize/4;
+ winner.save(cb);
+ },
+ function(saved, num, cb) {
+ closeChal(req.params.cid, {broken: 'CHALLENGE_CLOSED', winner: saved.profile.name}, cb);
+ }
+ ], function(){
if (err) return res.json(500, {err: err});
res.send(200);
})
diff --git a/src/models/task.js b/src/models/task.js
index 3935e0f232..97a46cdb94 100644
--- a/src/models/task.js
+++ b/src/models/task.js
@@ -28,7 +28,8 @@ var TaskSchema = new Schema({
streak: {type: Number, 'default': 0},
challenge: {
id: {type: 'String', ref:'Challenge'},
- broken: String // CHALLENGE_DELETED, TASK_DELETED, UNSUBSCRIBED, etc
+ broken: String, // CHALLENGE_DELETED, TASK_DELETED, UNSUBSCRIBED, CHALLENGE_CLOSED
+ winner: String // user.profile.name
// group: {type: 'Strign', ref: 'Group'} // if we restore this, rename `id` above to `challenge`
}
}, {
diff --git a/src/models/user.js b/src/models/user.js
index 78d2276fb3..23dee6f247 100644
--- a/src/models/user.js
+++ b/src/models/user.js
@@ -36,7 +36,9 @@ var UserSchema = new Schema({
helpedHabit: Boolean,
ultimateGear: Boolean,
beastMaster: Boolean,
- streak: Number
+ veteran: Boolean,
+ streak: Number,
+ challenges: Array
},
auth: {
facebook: Schema.Types.Mixed,
diff --git a/views/shared/profiles/achievements.jade b/views/shared/profiles/achievements.jade
index 3678d69696..e85f222929 100644
--- a/views/shared/profiles/achievements.jade
+++ b/views/shared/profiles/achievements.jade
@@ -74,4 +74,14 @@
h5 Original User!
small
| One of the very original early adopters, Talk about alpha tester!
- hr
\ No newline at end of file
+ hr
+
+ div(ng-if='profile.achievements.challenges || user._id == profile._id')
+ // This is a very strange icon to use. revisit
+ .achievement.achievement-karaoke(ng-show='profile.achievements.challenges')
+ div(ng-class='{muted: !profile.achievements.challenges}')
+ h5 Was the winner in the following challenges
+ ul
+ li(ng-repeat='chal in profile.achievements.challenges') {{chal}}
+ hr
+
diff --git a/views/shared/tasks/task.jade b/views/shared/tasks/task.jade
index f88d9a238f..fde272458e 100644
--- a/views/shared/tasks/task.jade
+++ b/views/shared/tasks/task.jade
@@ -75,6 +75,12 @@ li(ng-repeat='task in obj[list.type+"s"]', class='task {{taskClasses(task, user.
a(ng-click='unlink(task, "keep-all")') Keep Them
| |
a(ng-click='unlink(task, "remove-all")') Remove Them
+ div(ng-if='task.challenge.broken=="CHALLENGE_CLOSED"')
+ p. This challenge has been completed, and the winner was {{task.challenge.winner}}!. What to do with the orphan tasks?
+ p
+ a(ng-click='unlink(task, "keep-all")') Keep Them
+ | |
+ a(ng-click='unlink(task, "remove-all")') Remove Them
//-div(ng-if='task.challenge.broken=="UNSUBSCRIBED"')
p Broken Challenge Link: this task was part of a challenge, but you have unsubscribed from the challenge. What to do with the orphan tasks?
p