2013-08-29 05:45:19 +00:00
/* @see ./routes.coffee for routing*/
2013-10-06 23:52:54 +00:00
var url = require ( 'url' ) ;
2013-10-13 16:46:22 +00:00
var ipn = require ( 'paypal-ipn' ) ;
2013-08-29 05:45:19 +00:00
var _ = require ( 'lodash' ) ;
var nconf = require ( 'nconf' ) ;
var async = require ( 'async' ) ;
var algos = require ( 'habitrpg-shared/script/algos' ) ;
var helpers = require ( 'habitrpg-shared/script/helpers' ) ;
var items = require ( 'habitrpg-shared/script/items' ) ;
2013-09-04 04:20:49 +00:00
var validator = require ( 'validator' ) ;
2013-08-29 05:45:19 +00:00
var check = validator . check ;
var sanitize = validator . sanitize ;
var User = require ( './../models/user' ) . model ;
var Group = require ( './../models/group' ) . model ;
2013-10-27 22:27:01 +00:00
var Challenge = require ( './../models/challenge' ) . model ;
2013-08-29 05:45:19 +00:00
var api = module . exports ;
2013-09-06 04:28:18 +00:00
// FIXME put this in a proper location
api . marketBuy = function ( req , res , next ) {
var user = res . locals . user ,
type = req . query . type ,
item = req . body ;
if ( ! _ . contains ( [ 'hatchingPotion' , 'egg' ] , req . query . type ) )
return res . json ( 400 , { err : "Type must be in 'hatchingPotion' or 'egg'" } ) ;
var item ;
if ( type == 'egg' ) {
if ( ! user . items && ! user . items . eggs ) user . items . eggs = [ ] ;
user . items . eggs . push ( item ) ;
} else {
if ( ! user . items && ! user . items . hatchingPotions ) user . items . hatchingPotions = [ ] ;
user . items . hatchingPotions . push ( item . name ) ;
}
user . markModified ( 'items' ) ; // I still don't get when this is necessary and when not..
user . balance -= ( item . value / 4 ) ;
user . save ( function ( err , saved ) {
if ( err ) return res . json ( 500 , { err : err } ) ;
res . json ( saved ) ;
} )
}
2013-08-29 05:45:19 +00:00
/ *
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
Tasks
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
* /
/ *
Local Methods
-- -- -- -- -- -- -- -
* /
/ *
Validate task
* /
api . verifyTaskExists = function ( req , res , next ) {
2013-10-27 00:23:52 +00:00
// If we're updating, get the task from the user
var task = res . locals . user . tasks [ req . params . id ] ;
if ( _ . isEmpty ( task ) ) return res . json ( 400 , { err : "No task found." } ) ;
2013-08-29 05:45:19 +00:00
res . locals . task = task ;
return next ( ) ;
} ;
function deleteTask ( user , task ) {
2013-10-27 00:23:52 +00:00
user [ task . type + 's' ] . id ( task . id ) . remove ( ) ;
2013-08-29 05:45:19 +00:00
} ;
2013-10-27 00:23:52 +00:00
function addTask ( user , task ) {
2013-11-01 19:45:13 +00:00
task = helpers . taskDefaults ( task ) ;
user [ task . type + 's' ] . unshift ( task ) ;
return task ;
2013-10-27 00:23:52 +00:00
}
2013-08-29 05:45:19 +00:00
/ *
API Routes
-- -- -- -- -- -- -- -
* /
2013-10-27 22:27:01 +00:00
var syncScoreToChallenge = function ( task , delta ) {
2013-11-01 03:37:56 +00:00
if ( ! task . challenge || ! task . challenge . id || task . challenge . broken ) return ;
2013-10-31 17:22:57 +00:00
if ( task . type == 'reward' ) return ; // we don't want to update the reward GP cost
2013-10-27 22:27:01 +00:00
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 ( ) ;
} ) ;
}
2013-08-29 05:45:19 +00:00
2013-09-04 00:08:49 +00:00
/ * *
2013-08-29 05:45:19 +00:00
This is called form deprecated . coffee ' s score function , and the req . headers are setup properly to handle the login
Export it also so we can call it from deprecated . coffee
* /
2013-09-04 00:08:49 +00:00
api . scoreTask = function ( req , res , next ) {
2013-10-27 00:23:52 +00:00
var id = req . params . id ,
direction = req . params . direction ,
user = res . locals . user ,
task ;
2013-08-29 05:45:19 +00:00
2013-09-04 00:08:49 +00:00
// Send error responses for improper API call
2013-10-27 00:23:52 +00:00
if ( ! id ) return res . json ( 500 , { err : ':id required' } ) ;
2013-08-29 05:45:19 +00:00
if ( direction !== 'up' && direction !== 'down' ) {
2013-10-27 22:27:01 +00:00
if ( direction == 'unlink' ) return next ( ) ;
2013-10-27 00:23:52 +00:00
return res . json ( 500 , { err : ":direction must be 'up' or 'down'" } ) ;
2013-08-29 05:45:19 +00:00
}
2013-10-27 00:23:52 +00:00
// If exists already, score it
2013-11-01 19:45:13 +00:00
if ( task = user . tasks [ id ] ) {
2013-10-27 00:23:52 +00:00
// Set completed if type is daily or todo and task exists
2013-11-01 19:45:13 +00:00
if ( task . type === 'daily' || task . type === 'todo' ) {
task . completed = direction === 'up' ;
2013-08-29 05:45:19 +00:00
}
} else {
2013-10-27 00:23:52 +00:00
// If it doesn't exist, this is likely a 3rd party up/down - create a new one, then score it
2013-08-29 05:45:19 +00:00
task = {
id : id ,
value : 0 ,
2013-10-27 00:23:52 +00:00
type : req . body . type || 'habit' ,
text : req . body . title || id ,
2013-08-29 05:45:19 +00:00
notes : "This task was created by a third-party service. Feel free to edit, it won't harm the connection to that service. Additionally, multiple services may piggy-back off this task."
} ;
if ( task . type === 'habit' ) {
task . up = task . down = true ;
}
2013-10-27 00:23:52 +00:00
if ( task . type === 'daily' || task . type === 'todo' ) {
2013-08-29 05:45:19 +00:00
task . completed = direction === 'up' ;
}
2013-11-01 19:45:13 +00:00
task = addTask ( user , task ) ;
2013-08-29 05:45:19 +00:00
}
2013-10-27 00:23:52 +00:00
var delta = algos . score ( user , task , direction ) ;
2013-10-27 22:27:01 +00:00
//user.markModified('flags');
2013-09-17 18:44:02 +00:00
user . save ( function ( err , saved ) {
if ( err ) return res . json ( 500 , { err : err } ) ;
res . json ( 200 , _ . extend ( {
2013-08-29 05:45:19 +00:00
delta : delta
} , saved . toJSON ( ) . stats ) ) ;
} ) ;
2013-10-27 22:27:01 +00:00
// if it's a challenge task, sync the score
syncScoreToChallenge ( task , delta ) ;
2013-08-29 05:45:19 +00:00
} ;
2013-10-27 00:23:52 +00:00
/ * *
* Get all tasks
* /
2013-08-29 05:45:19 +00:00
api . getTasks = function ( req , res , next ) {
2013-10-27 00:23:52 +00:00
if ( req . query . type ) {
return res . json ( user [ req . query . type + 's' ] ) ;
} else {
return res . json ( _ . toArray ( user . tasks ) ) ;
}
2013-08-29 05:45:19 +00:00
} ;
2013-10-27 00:23:52 +00:00
/ * *
* Get Task
* /
2013-08-29 05:45:19 +00:00
api . getTask = function ( req , res , next ) {
2013-10-27 00:23:52 +00:00
var task = res . locals . user . tasks [ req . params . id ] ;
if ( _ . isEmpty ( task ) ) return res . json ( 400 , { err : "No task found." } ) ;
2013-08-29 05:45:19 +00:00
return res . json ( 200 , task ) ;
} ;
2013-10-27 00:23:52 +00:00
/ * *
* Delete Task
* /
2013-08-29 05:45:19 +00:00
api . deleteTask = function ( req , res , next ) {
deleteTask ( res . locals . user , res . locals . task ) ;
2013-09-02 22:40:20 +00:00
res . locals . user . save ( function ( err ) {
if ( err ) return res . json ( 500 , { err : err } ) ;
res . send ( 204 ) ;
2013-08-29 05:45:19 +00:00
} ) ;
} ;
/ *
Update Task
* /
api . updateTask = function ( req , res , next ) {
2013-10-27 00:23:52 +00:00
var user = res . locals . user ;
var task = user . tasks [ req . params . id ] ;
user [ task . type + 's' ] [ _ . findIndex ( user [ task . type + 's' ] , { id : task . id } ) ] = req . body ;
user . save ( function ( err , saved ) {
if ( err ) return res . json ( 500 , { err : err } )
return res . json ( 200 , saved . tasks [ id ] ) ;
2013-08-29 05:45:19 +00:00
} ) ;
} ;
2013-10-27 00:23:52 +00:00
/ * *
* Update tasks ( plural ) . This will update , add new , delete , etc all at once .
* TODO Should we keep this ?
* /
2013-08-29 05:45:19 +00:00
api . updateTasks = function ( req , res , next ) {
2013-10-27 00:23:52 +00:00
var user = res . locals . user ;
var tasks = req . body ;
2013-08-29 05:45:19 +00:00
_ . each ( tasks , function ( task , idx ) {
if ( task . id ) {
2013-10-27 00:23:52 +00:00
// delete
2013-08-29 05:45:19 +00:00
if ( task . del ) {
deleteTask ( user , task ) ;
2013-10-27 00:23:52 +00:00
task = { deleted : true } ;
2013-08-29 05:45:19 +00:00
} else {
2013-10-27 00:23:52 +00:00
// Update
// updateTask(user, task.id, task); //FIXME
2013-08-29 05:45:19 +00:00
}
} else {
2013-10-27 00:23:52 +00:00
// Create
2013-08-29 05:45:19 +00:00
task = addTask ( user , task ) ;
}
2013-10-27 00:23:52 +00:00
tasks [ idx ] = task ;
2013-08-29 05:45:19 +00:00
} ) ;
2013-10-27 00:23:52 +00:00
user . save ( function ( err , saved ) {
if ( err ) return res . json ( 500 , { err : err } ) ;
2013-08-29 05:45:19 +00:00
return res . json ( 201 , tasks ) ;
} ) ;
} ;
api . createTask = function ( req , res , next ) {
2013-10-27 00:23:52 +00:00
var user = res . locals . user ;
var task = addTask ( user , req . body ) ;
user . save ( function ( err , saved ) {
if ( err ) return res . json ( 500 , { err : err } ) ;
2013-08-29 05:45:19 +00:00
return res . json ( 201 , task ) ;
} ) ;
} ;
api . sortTask = function ( req , res , next ) {
2013-10-27 00:23:52 +00:00
var id = req . params . id ;
var to = req . body . to , from = req . body . from , type = req . body . type ;
var user = res . locals . user ;
user [ type + 's' ] . splice ( to , 0 , user [ type + 's' ] . splice ( from , 1 ) [ 0 ] ) ;
user . save ( function ( err , saved ) {
if ( err ) return res . json ( 500 , { err : err } ) ;
return res . json ( 200 , saved . toJSON ( ) [ type + 's' ] ) ;
2013-08-29 05:45:19 +00:00
} ) ;
} ;
api . clearCompleted = function ( req , res , next ) {
2013-10-27 00:23:52 +00:00
var user = res . locals . user ;
user . todos = _ . where ( user . todos , { completed : false } ) ;
2013-08-29 05:45:19 +00:00
return user . save ( function ( err , saved ) {
2013-10-27 00:23:52 +00:00
if ( err ) return res . json ( 500 , { err : err } ) ;
2013-08-29 05:45:19 +00:00
return res . json ( saved ) ;
} ) ;
} ;
/ *
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
Items
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
* /
api . buy = function ( req , res , next ) {
var hasEnough , type , user ;
user = res . locals . user ;
type = req . params . type ;
if ( type !== 'weapon' && type !== 'armor' && type !== 'head' && type !== 'shield' && type !== 'potion' ) {
2013-10-27 00:23:52 +00:00
return res . json ( 400 , { err : ":type must be in one of: 'weapon', 'armor', 'head', 'shield', 'potion'" } ) ;
2013-08-29 05:45:19 +00:00
}
hasEnough = items . buyItem ( user , type ) ;
if ( hasEnough ) {
return user . save ( function ( err , saved ) {
2013-10-27 00:23:52 +00:00
if ( err ) return res . json ( 500 , { err : err } ) ;
2013-08-29 05:45:19 +00:00
return res . json ( 200 , saved . toJSON ( ) . items ) ;
} ) ;
} else {
2013-10-27 00:23:52 +00:00
return res . json ( 200 , { err : "Not enough GP" } ) ;
2013-08-29 05:45:19 +00:00
}
} ;
/ *
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
User
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
* /
2013-10-27 00:23:52 +00:00
/ * *
* Get User
* /
2013-08-29 05:45:19 +00:00
api . getUser = function ( req , res , next ) {
2013-09-04 14:19:55 +00:00
var user = res . locals . user . toJSON ( ) ;
2013-08-29 05:45:19 +00:00
user . stats . toNextLevel = algos . tnl ( user . stats . lvl ) ;
user . stats . maxHealth = 50 ;
delete user . apiToken ;
if ( user . auth ) {
delete user . auth . hashed _password ;
delete user . auth . salt ;
}
return res . json ( 200 , user ) ;
} ;
2013-10-27 00:23:52 +00:00
/ * *
* Update user
* FIXME add documentation here
2013-08-29 05:45:19 +00:00
* /
api . updateUser = function ( req , res , next ) {
var acceptableAttrs , errors , user ;
user = res . locals . user ;
errors = [ ] ;
if ( _ . isEmpty ( req . body ) ) {
return res . json ( 200 , user ) ;
}
/ *
# FIXME we need to do some crazy sanitiazation if they ' re using the old ` PUT /user {data} ` method .
# The new ` PUT /user {'stats.hp':50}
# FIXME - one - by - one we want to widdle down this list , instead replacing each needed set path with API operations
# There 's a trick here. In order to prevent prevent clobering top-level paths, we add `.` to make sure they' re
# sending bodies as { "set.this.path" : value } instead of { set : { this : { path : value } } } . Permit lastCron since it ' s top - level
# Note : custom is for 3 rd party apps
* /
2013-09-09 03:28:34 +00:00
acceptableAttrs = 'tasks. achievements. filters. flags. invitations. items. lastCron party. preferences. profile. stats. tags custom.' . split ( ' ' ) ;
2013-08-29 05:45:19 +00:00
_ . each ( req . body , function ( v , k ) {
if ( ( _ . find ( acceptableAttrs , function ( attr ) {
return k . indexOf ( attr ) === 0 ;
} ) ) != null ) {
if ( _ . isObject ( v ) ) {
errors . push ( "Value for " + k + " was an object. Be careful here, you could clobber stuff." ) ;
}
helpers . dotSet ( k , v , user ) ;
} else {
errors . push ( "path `" + k + "` was not saved, as it's a protected path. Make sure to send `PUT /api/v1/user` request bodies as `{'set.this.path':value}` instead of `{set:{this:{path:value}}}`" ) ;
}
return true ;
} ) ;
return user . save ( function ( err ) {
if ( ! _ . isEmpty ( errors ) ) {
return res . json ( 500 , {
err : errors
} ) ;
}
if ( err ) {
return res . json ( 500 , {
err : err
} ) ;
}
return res . json ( 200 , user ) ;
} ) ;
} ;
api . cron = function ( req , res , next ) {
2013-10-27 00:23:52 +00:00
var user = res . locals . user ;
2013-08-29 05:45:19 +00:00
algos . cron ( user ) ;
2013-08-29 16:07:29 +00:00
if ( user . isModified ( ) ) {
res . locals . wasModified = true ;
2013-09-09 01:45:46 +00:00
user . auth . timestamps . loggedin = new Date ( ) ;
2013-08-29 16:07:29 +00:00
}
user . save ( next ) ;
2013-08-29 05:45:19 +00:00
} ;
api . revive = function ( req , res , next ) {
2013-10-27 00:23:52 +00:00
var user = res . locals . user ;
2013-08-29 05:45:19 +00:00
algos . revive ( user ) ;
2013-10-27 00:23:52 +00:00
user . save ( function ( err , saved ) {
if ( err ) return res . json ( 500 , { err : err } ) ;
2013-08-29 05:45:19 +00:00
return res . json ( 200 , saved ) ;
} ) ;
} ;
api . reroll = function ( req , res , next ) {
2013-10-27 00:23:52 +00:00
var user = res . locals . user ;
if ( user . balance < 1 ) return res . json ( 401 , { err : "Not enough tokens." } ) ;
2013-08-29 05:45:19 +00:00
user . balance -= 1 ;
2013-10-27 00:23:52 +00:00
_ . each ( [ 'habits' , 'dailys' , 'todos' ] , function ( type ) {
_ . each ( [ user [ type + 's' ] ] , function ( task ) {
task . value = 0 ;
} )
} )
2013-08-29 05:45:19 +00:00
user . stats . hp = 50 ;
2013-10-27 00:23:52 +00:00
user . save ( function ( err , saved ) {
if ( err ) return res . json ( 500 , { err : err } ) ;
2013-08-29 05:45:19 +00:00
return res . json ( 200 , saved ) ;
} ) ;
} ;
2013-09-08 19:11:04 +00:00
api . reset = function ( req , res ) {
var user = res . locals . user ;
2013-10-27 00:23:52 +00:00
user . habits = [ ] ;
user . dailys = [ ] ;
user . todos = [ ] ;
user . rewards = [ ] ;
2013-09-08 19:11:04 +00:00
user . stats . hp = 50 ;
user . stats . lvl = 1 ;
user . stats . gp = 0 ;
user . stats . exp = 0 ;
user . items . armor = 0 ;
user . items . weapon = 0 ;
user . items . head = 0 ;
user . items . shield = 0 ;
user . save ( function ( err , saved ) {
if ( err ) return res . json ( 500 , { err : err } ) ;
res . json ( saved ) ;
} )
2013-09-08 19:17:49 +00:00
}
2013-09-08 19:11:04 +00:00
2013-09-08 19:17:49 +00:00
api [ 'delete' ] = function ( req , res ) {
res . locals . user . remove ( function ( err ) {
if ( err ) return res . json ( 500 , { err : err } ) ;
res . send ( 200 ) ;
} )
2013-09-08 19:11:04 +00:00
}
2013-10-22 19:19:43 +00:00
/ *
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
Unlock Preferences
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
* /
api . unlock = function ( req , res ) {
var user = res . locals . user ;
2013-10-22 20:59:30 +00:00
var path = req . query . path ;
var fullSet = ~ path . indexOf ( ',' ) ;
// 5G per set, 2G per individual
cost = fullSet ? 1.25 : 0.5 ;
if ( user . balance < cost )
2013-10-22 19:19:43 +00:00
return res . json ( 401 , { err : 'Not enough gems' } ) ;
2013-10-22 20:59:30 +00:00
if ( fullSet ) {
var paths = path . split ( ',' ) ;
_ . each ( paths , function ( p ) {
helpers . dotSet ( 'purchased.' + p , true , user ) ;
} ) ;
} else {
if ( helpers . dotGet ( 'purchased.' + path , user ) === true )
return res . json ( 401 , { err : 'User already purchased that' } ) ;
helpers . dotSet ( 'purchased.' + path , true , user ) ;
}
user . balance -= cost ;
2013-10-22 19:19:43 +00:00
user . _ _v ++ ;
2013-10-22 20:37:55 +00:00
user . markModified ( 'purchased' ) ;
2013-10-22 19:19:43 +00:00
user . save ( function ( err , saved ) {
if ( err ) res . json ( 500 , { err : err } ) ;
res . send ( 200 ) ;
} )
}
/ *
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
Buy Gems
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
* /
2013-10-31 22:14:19 +00:00
api . addTenGems = function ( req , res ) {
var user = res . locals . user ;
user . balance += 2.5 ;
user . save ( function ( err ) {
if ( err ) return res . json ( 500 , { err : err } ) ;
res . send ( 204 ) ;
} )
}
2013-08-29 05:45:19 +00:00
/ *
Setup Stripe response when posting payment
* /
api . buyGems = function ( req , res ) {
var api _key = nconf . get ( 'STRIPE_API_KEY' ) ;
var stripe = require ( "stripe" ) ( api _key ) ;
var token = req . body . id ;
// console.dir {token:token, req:req}, 'stripe'
async . waterfall ( [
function ( cb ) {
stripe . charges . create ( {
amount : "500" , // $5
currency : "usd" ,
card : token
} , cb ) ;
} ,
function ( response , cb ) {
res . locals . user . balance += 5 ;
2013-10-23 01:50:50 +00:00
res . locals . user . purchased . ads = true ;
2013-08-29 05:45:19 +00:00
res . locals . user . save ( cb ) ;
}
] , function ( err , saved ) {
if ( err ) return res . send ( 500 , err . toString ( ) ) ; // don't json this, let toString() handle errors
res . send ( 200 , saved ) ;
} ) ;
} ;
2013-10-06 23:52:54 +00:00
api . buyGemsPaypalIPN = function ( req , res ) {
2013-10-13 16:46:22 +00:00
res . send ( 200 ) ;
2013-10-06 23:52:54 +00:00
ipn . verify ( req . body , function callback ( err , msg ) {
if ( err ) {
console . error ( msg ) ;
res . send ( 500 , msg ) ;
} else {
if ( req . body . payment _status == 'Completed' ) {
//Payment has been confirmed as completed
var parts = url . parse ( req . body . custom , true ) ;
var uid = parts . query . uid ; //, apiToken = query.apiToken;
if ( ! uid ) throw new Error ( "uuid or apiToken not found when completing paypal transaction" ) ;
User . findById ( uid , function ( err , user ) {
if ( err ) throw err ;
if ( _ . isEmpty ( user ) ) throw "user not found with uuid " + uuid + " when completing paypal transaction"
user . balance += 5 ;
2013-10-23 01:50:50 +00:00
user . purchased . ads = true ;
2013-10-06 23:52:54 +00:00
user . save ( ) ;
2013-10-13 16:46:22 +00:00
console . log ( 'PayPal transaction completed and user updated' ) ;
2013-10-06 23:52:54 +00:00
} ) ;
}
}
} ) ;
}
2013-09-09 04:04:02 +00:00
/ *
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
Tags
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
* /
api . deleteTag = function ( req , res ) {
var user = res . locals . user ;
2013-10-24 16:21:34 +00:00
var tid = req . params . tid || req . body . tag ;
var i = _ . findIndex ( user . tags , { id : tid } ) ;
2013-09-09 04:04:02 +00:00
if ( ~ i ) {
var tag = user . tags [ i ] ;
2013-09-09 04:13:11 +00:00
delete user . filters [ tag . id ] ;
2013-09-09 04:04:02 +00:00
user . tags . splice ( i , 1 ) ;
// remove tag from all tasks
2013-10-27 00:23:52 +00:00
_ . each ( [ 'habits' , 'dailys' , 'todos' , 'rewards' ] , function ( type ) {
_ . each ( user [ type ] , function ( task ) {
delete task . tags [ tag . id ] ;
} )
} )
2013-09-09 04:04:02 +00:00
user . save ( function ( err , saved ) {
2013-10-24 16:21:34 +00:00
if ( err ) return res . json ( 500 , { err : err } ) ;
// Need to use this until we found a way to update the ui for tasks when a tag is deleted
res . locals . wasModified = true ;
2013-09-09 04:04:02 +00:00
res . send ( 200 ) ;
2013-10-24 16:21:34 +00:00
} ) ;
2013-09-09 04:04:02 +00:00
} else {
res . json ( 400 , { err : 'Tag not found' } ) ;
}
}
2013-08-29 05:45:19 +00:00
/ *
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
Batch Update
Run a bunch of updates all at once
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
* /
api . batchUpdate = function ( req , res , next ) {
2013-10-27 00:23:52 +00:00
var user = res . locals . user ;
var oldSend = res . send ;
var oldJson = res . json ;
var performAction = function ( action , cb ) {
// TODO come up with a more consistent approach here. like:
// req.body=action.data; delete action.data; _.defaults(req.params, action)
// Would require changing action.dir on mobile app
req . params . id = action . data && action . data . id ;
2013-08-29 05:45:19 +00:00
req . params . direction = action . dir ;
req . params . type = action . type ;
req . body = action . data ;
res . send = res . json = function ( code , data ) {
if ( _ . isNumber ( code ) && code >= 400 ) {
console . error ( {
code : code ,
data : data
} ) ;
}
2013-09-02 22:40:20 +00:00
//FIXME send error messages down
2013-08-29 05:45:19 +00:00
return cb ( ) ;
} ;
switch ( action . op ) {
case "score" :
2013-09-02 21:15:12 +00:00
api . scoreTask ( req , res ) ;
2013-09-02 22:40:20 +00:00
break ;
2013-08-29 05:45:19 +00:00
case "buy" :
2013-09-02 21:15:12 +00:00
api . buy ( req , res ) ;
2013-09-02 22:40:20 +00:00
break ;
2013-08-29 05:45:19 +00:00
case "sortTask" :
2013-09-02 21:15:12 +00:00
api . verifyTaskExists ( req , res , function ( ) {
api . sortTask ( req , res ) ;
2013-08-29 05:45:19 +00:00
} ) ;
2013-09-02 22:40:20 +00:00
break ;
2013-08-29 05:45:19 +00:00
case "addTask" :
2013-09-02 21:15:12 +00:00
api . createTask ( req , res ) ;
2013-09-02 22:40:20 +00:00
break ;
2013-08-29 05:45:19 +00:00
case "delTask" :
2013-09-02 21:15:12 +00:00
api . verifyTaskExists ( req , res , function ( ) {
api . deleteTask ( req , res ) ;
2013-08-29 05:45:19 +00:00
} ) ;
2013-09-02 22:40:20 +00:00
break ;
2013-08-29 05:45:19 +00:00
case "set" :
2013-09-02 21:15:12 +00:00
api . updateUser ( req , res ) ;
2013-09-02 22:40:20 +00:00
break ;
2013-10-24 16:21:34 +00:00
case "delTag" :
api . deleteTag ( req , res ) ;
break ;
2013-08-29 05:45:19 +00:00
case "revive" :
2013-09-02 21:15:12 +00:00
api . revive ( req , res ) ;
2013-09-02 22:40:20 +00:00
break ;
2013-08-29 05:45:19 +00:00
case "clear-completed" :
2013-09-02 21:15:12 +00:00
api . clearCompleted ( req , res ) ;
2013-09-02 22:40:20 +00:00
break ;
2013-08-29 05:45:19 +00:00
case "reroll" :
2013-09-02 21:15:12 +00:00
api . reroll ( req , res ) ;
2013-09-02 22:40:20 +00:00
break ;
2013-08-29 05:45:19 +00:00
default :
2013-09-02 21:15:12 +00:00
cb ( ) ;
2013-09-02 22:40:20 +00:00
break ;
2013-08-29 05:45:19 +00:00
}
} ;
2013-10-27 00:23:52 +00:00
// Setup the array of functions we're going to call in parallel with async
var actions = _ . transform ( req . body || [ ] , function ( result , action ) {
2013-08-29 05:45:19 +00:00
if ( ! _ . isEmpty ( action ) ) {
2013-10-27 00:23:52 +00:00
result . push ( function ( cb ) {
performAction ( action , cb ) ;
2013-08-29 05:45:19 +00:00
} ) ;
}
} ) ;
2013-10-27 00:23:52 +00:00
// call all the operations, then return the user object to the requester
async . series ( actions , function ( err ) {
2013-08-29 05:45:19 +00:00
res . json = oldJson ;
res . send = oldSend ;
2013-10-27 00:23:52 +00:00
if ( err ) return res . json ( 500 , { err : err } ) ;
var response = user . toJSON ( ) ;
2013-08-29 05:45:19 +00:00
response . wasModified = res . locals . wasModified ;
2013-09-17 16:16:16 +00:00
if ( response . _tmp && response . _tmp . drop ) response . wasModified = true ;
2013-09-20 14:01:09 +00:00
// Send the response to the server
if ( response . wasModified ) {
res . json ( 200 , response ) ;
} else {
2013-09-20 14:09:55 +00:00
res . json ( 200 , { _v : response . _v } ) ;
2013-09-20 14:01:09 +00:00
}
2013-08-29 05:45:19 +00:00
} ) ;
} ;