From a078889d589f32817ec798a3cf9445822f793152 Mon Sep 17 00:00:00 2001 From: Tyler Renelle Date: Sun, 27 Oct 2013 15:27:01 -0700 Subject: [PATCH] challenges: sync score to challenge, lotsa bug fixes --- public/js/controllers/challengesCtrl.js | 53 ------------------------- public/js/controllers/tasksCtrl.js | 12 +++++- src/controllers/challenges.js | 10 +++-- src/controllers/user.js | 20 ++++++++-- src/models/task.js | 4 +- views/options/challenges.jade | 23 ++++------- views/shared/tasks/task.jade | 6 +-- 7 files changed, 45 insertions(+), 83 deletions(-) diff --git a/public/js/controllers/challengesCtrl.js b/public/js/controllers/challengesCtrl.js index 7f0e270cdf..7d9dd6b08a 100644 --- a/public/js/controllers/challengesCtrl.js +++ b/public/js/controllers/challengesCtrl.js @@ -119,50 +119,6 @@ habitrpg.controller("ChallengesCtrl", ['$scope', '$rootScope', 'User', 'Challeng // chart = new google.visualization.LineChart $(".challenge-#{chal.id}-member-#{member.id}-history-#{task.id}")[0] // chart.draw(data, options) - /** - * Sync user to challenge (when they score, add to statistics) - */ - // TODO this needs to be moved to the server. Either: - // 1. Calculate on load (simplest, but bad performance) - // 2. Updated from user score API -// app.model.on("change", "_page.user.priv.tasks.*.value", function(id, value, previous, passed) { -// /* Sync to challenge, but do it later*/ -// -// var _this = this; -// return async.nextTick(function() { -// var chal, chalTask, chalUser, ctx, cu, model, pub, task, tobj; -// model = app.model; -// ctx = { -// model: model -// }; -// task = model.at("_page.user.priv.tasks." + id); -// tobj = task.get(); -// pub = model.get("_page.user.pub"); -// if (((chalTask = helpers.taskInChallenge.call(ctx, tobj)) != null) && chalTask.get()) { -// chalTask.increment("value", value - previous); -// chal = model.at("groups." + tobj.group.id + ".challenges." + tobj.challenge); -// chalUser = function() { -// return helpers.indexedAt.call(ctx, chal.path(), 'members', { -// id: pub.id -// }); -// }; -// cu = chalUser(); -// if (!(cu != null ? cu.get() : void 0)) { -// chal.push("members", { -// id: pub.id, -// name: model.get(pub.profile.name) -// }); -// cu = model.at(chalUser()); -// } else { -// cu.set('name', pub.profile.name); -// } -// return cu.set("" + tobj.type + "s." + tobj.id, { -// value: tobj.value, -// history: tobj.history -// }); -// } -// }); -// }); /* -------------------------- @@ -170,15 +126,6 @@ habitrpg.controller("ChallengesCtrl", ['$scope', '$rootScope', 'User', 'Challeng -------------------------- */ - $scope.unlink = function(task, keep) { - // TODO move this to userServices, turn userSerivces.user into ng-resource - $http.post(API_URL + '/api/v1/user/task/' + task.id + '/unlink', {keep:keep}) - .success(function(){ - debugger - User.log({}); - }); - }; - $scope.unsubscribe = function(keep) { if (keep == 'cancel') { $scope.selectedChal = undefined; diff --git a/public/js/controllers/tasksCtrl.js b/public/js/controllers/tasksCtrl.js index a33919ce0c..a4a72e8849 100644 --- a/public/js/controllers/tasksCtrl.js +++ b/public/js/controllers/tasksCtrl.js @@ -1,7 +1,7 @@ "use strict"; -habitrpg.controller("TasksCtrl", ['$scope', '$rootScope', '$location', 'User', 'Algos', 'Helpers', 'Notification', - function($scope, $rootScope, $location, User, Algos, Helpers, Notification) { +habitrpg.controller("TasksCtrl", ['$scope', '$rootScope', '$location', 'User', 'Algos', 'Helpers', 'Notification', '$http', 'API_URL', + function($scope, $rootScope, $location, User, Algos, Helpers, Notification, $http, API_URL) { $scope.score = function(task, direction) { if (task.type === "reward" && User.user.stats.gp < task.value){ return Notification.text('Not enough GP.'); @@ -94,6 +94,14 @@ habitrpg.controller("TasksCtrl", ['$scope', '$rootScope', '$location', 'User', ' $scope.editing = false; }; + $scope.unlink = function(task, keep) { + // TODO move this to userServices, turn userSerivces.user into ng-resource + $http.post(API_URL + '/api/v1/user/task/' + task.id + '/unlink?keep=' + keep) + .success(function(){ + User.log({}); + }); + }; + /* ------------------------ Items diff --git a/src/controllers/challenges.js b/src/controllers/challenges.js index 903f68f5b8..54af61e70a 100644 --- a/src/controllers/challenges.js +++ b/src/controllers/challenges.js @@ -139,7 +139,7 @@ var syncChalToUser = function(chal, user) { _.each(chal.tasks, function(task){ var type = task.type; _.defaults(task, {tags: tags, challenge:{}}); - _.defaults(task.challenge, {id:chal._id, broken:false}); + _.defaults(task.challenge, {id:chal._id}); if (user.tasks[task.id]) { _.merge(user.tasks[task.id], keepAttrs(task)); } else { @@ -213,8 +213,6 @@ api.leave = function(req, res){ Challenge.findByIdAndUpdate(cid, {$pull:{members:user._id}}, cb); }, function(chal, cb){ - // Remove challenge from user - //User.findByIdAndUpdate(user._id, {$pull:{challenges:cid}}, cb); var i = user.challenges.indexOf(cid) if (~i) user.challenges.splice(i,1); unlink(user, chal._id, keep) @@ -229,7 +227,11 @@ api.leave = function(req, res){ }); } -api.unlink = function(req, res) { +api.unlink = function(req, res, next) { + // they're scoring the task - commented out, we probably don't need it due to route ordering in api.js + //var urlParts = req.originalUrl.split('/'); + //if (_.contains(['up','down'], urlParts[urlParts.length -1])) return next(); + var user = res.locals.user; var tid = req.params.id; var cid = user.tasks[tid].challenge.id; diff --git a/src/controllers/user.js b/src/controllers/user.js index 54b92b20c3..bb89890807 100644 --- a/src/controllers/user.js +++ b/src/controllers/user.js @@ -1,8 +1,5 @@ /* @see ./routes.coffee for routing*/ -// fixme remove this junk, was coffeescript compiled (probably for IE8 compat) -var __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; - var url = require('url'); var ipn = require('paypal-ipn'); var _ = require('lodash'); @@ -16,6 +13,7 @@ var check = validator.check; var sanitize = validator.sanitize; var User = require('./../models/user').model; var Group = require('./../models/group').model; +var Challenge = require('./../models/challenge').model; var api = module.exports; // FIXME put this in a proper location @@ -82,6 +80,16 @@ function addTask(user, task) { --------------- */ +var syncScoreToChallenge = function(task, delta){ + if (!task.challenge || !task.challenge.id) return; + Challenge.findById(task.challenge.id, function(err, chal){ + if (err) throw err; + var t = chal.tasks[task.id] + t.value += delta; + t.history.push({value: t.value, date: +new Date}); + chal.save(); + }); +} /** This is called form deprecated.coffee's score function, and the req.headers are setup properly to handle the login @@ -96,6 +104,7 @@ api.scoreTask = function(req, res, next) { // Send error responses for improper API call if (!id) return res.json(500, {err: ':id required'}); if (direction !== 'up' && direction !== 'down') { + if (direction == 'unlink') return next(); return res.json(500, {err: ":direction must be 'up' or 'down'"}); } // If exists already, score it @@ -124,13 +133,16 @@ api.scoreTask = function(req, res, next) { } task = user.tasks[id]; var delta = algos.score(user, task, direction); - //user.markModified('flags'); + //user.markModified('flags'); user.save(function(err, saved) { if (err) return res.json(500, {err: err}); res.json(200, _.extend({ delta: delta }, saved.toJSON().stats)); }); + + // if it's a challenge task, sync the score + syncScoreToChallenge(task, delta); }; /** diff --git a/src/models/task.js b/src/models/task.js index cbaecb6491..6547170c3a 100644 --- a/src/models/task.js +++ b/src/models/task.js @@ -28,8 +28,8 @@ var TaskSchema = new Schema({ streak: {type: Number, 'default': 0}, challenge: { id: {type: 'String', ref:'Challenge'}, - broken: {type: Boolean, 'default': false} - // group: {type: 'Strign', redf: 'Group'} // if we restore this, rename `id` above to `challenge` + broken: String // CHALLENGE_DELETED, TASK_DELETED, UNSUBSCRIBED, etc + // group: {type: 'Strign', ref: 'Group'} // if we restore this, rename `id` above to `challenge` } }); diff --git a/views/options/challenges.jade b/views/options/challenges.jade index 823978c81a..41408e98f2 100644 --- a/views/options/challenges.jade +++ b/views/options/challenges.jade @@ -2,22 +2,15 @@ .span2.well h4 Filters ul + li(ng-repeat='group in groups') + input(type='checkbox', ng-model='search.group') + | {{group.name}} li - input(type='checkbox', checked='checked') - .label.label-warning todo - | Party + input(type='checkbox', ng-model='search.members') + | Subscribed (TODO) li - input(type='checkbox', checked='checked') - .label.label-warning todo - | (list groups) - li - input(type='checkbox', checked='checked') - .label.label-warning todo - | Subscribed - li - input(type='checkbox', checked='checked') - .label.label-warning todo - | Available + input(type='checkbox', ng-model='search.members') + | Available (TODO) .span10 // Creation form a.btn.btn-success(ng-click='create()') Create Challenge @@ -33,7 +26,7 @@ habitrpg-tasks(main=false, obj='newChallenge') // Challenges list - .accordion-group(ng-repeat='challenge in challenges', ng-init='locked=true') + .accordion-group(ng-repeat='challenge in challenges | filter:search', ng-init='locked=true') .accordion-heading ul.pull-right.challenge-accordion-header-specs li {{challenge.members.length}} Subscribers diff --git a/views/shared/tasks/task.jade b/views/shared/tasks/task.jade index 3e18c28a5a..e8f62d8d0c 100644 --- a/views/shared/tasks/task.jade +++ b/views/shared/tasks/task.jade @@ -64,15 +64,15 @@ li(ng-repeat='task in list.tasks', class='task {{taskClasses(task, user.filters, div(ng-if='task.challenge.broken=="TASK_DELETED"') p Broken Challenge Link: this task was part of a challenge, but has been removed from it. What would you like to do? p - a(ng-click="unlink(task, 'keep')") Keep It + a(ng-click='unlink(task, "keep")') Keep It |  |  a(ng-click="remove(list, $index)") Remove It div(ng-if='task.challenge.broken=="CHALLENGE_DELETED"') p Broken Challenge Link: this task was part of a challenge, but the challenge (or group) has been deleted. What to do with the orphan tasks? p - a(ng-click="unlink(task 'keep-all')") Keep Them + a(ng-click='unlink(task, "keep-all")') Keep Them |  |  - a(ng-click="unlink(task, 'remove-all')") Remove 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