Merge branch 'apiv2' into develop

This commit is contained in:
Tyler Renelle 2013-08-04 16:33:29 -04:00
commit 3ec7ba1a5a
5 changed files with 95 additions and 52 deletions

3
.gitignore vendored
View file

@ -5,4 +5,5 @@ node_modules
*.swp
.idea*
config.json
npm-debug.log
npm-debug.log
lib

View file

@ -26,7 +26,7 @@
"expect.js": "~0.2.0",
"derby-i18n": "git://github.com/switz/derby-i18n#master",
"relative-date": "~1.1.1",
"lodash": "~1.2.1",
"lodash": "~1.3.1",
"async": "~0.2.9",
"optimist": "~0.5.2"
},

View file

@ -4,7 +4,7 @@ items = require('habitrpg-shared/script/items').items
helpers = require('habitrpg-shared/script/helpers')
module.exports.batchTxn = batchTxn = (model, cb, options) ->
user = model.at("_user")
user = options?.user or model.at("_user")
uObj = hydrate(user.get()) # see https://github.com/codeparty/racer/issues/116
batch =
set: (k,v) -> helpers.dotSet(k,v,uObj); paths[k] = true
@ -19,6 +19,7 @@ module.exports.batchTxn = batchTxn = (model, cb, options) ->
unless _.isEmpty paths
setOps = _.reduce paths, ((m,v,k)-> m[k] = helpers.dotGet(k,uObj);m), {}
user.set "update__", setOps, options?.done
else options?.done?()
ret
#TODO put this in habitrpg-shared

View file

@ -8,14 +8,28 @@ validator = require 'derby-auth/node_modules/validator'
check = validator.check
sanitize = validator.sanitize
utils = require 'derby-auth/utils'
misc = require '../app/misc'
NO_TOKEN_OR_UID = err: "You must include a token and uid (user id) in your request"
NO_USER_FOUND = err: "No user found."
addTask = (user, task) ->
addTask = (user, task, cb) ->
task.type ?= 'habit'
tid = user.add "tasks", task
user.push "#{task.type}Ids", tid
tid = user.add "tasks", task, ->
user.unshift "#{task.type}Ids", tid, cb
deleteTask = (user, task, cb) ->
user.del "tasks.#{task.id}", ->
taskIds = user.get "#{task.type}Ids"
user.remove "#{task.type}Ids", taskIds.indexOf(task.id), 1, cb
score = (model, user, taskId, direction, cb) ->
delta = 0
misc.batchTxn model, (uObj, paths) ->
tObj = uObj.tasks[taskId]
delta = algos.score(uObj, tObj, direction, {paths})
, {user, done:cb}
delta
# ---------- /api/v1 API ------------
# Every url added beneath router is prefaced by /api/v1
@ -202,12 +216,7 @@ router.put '/user/task/:id', auth, validateTask, (req, res) ->
DELETE /user/task/:id
###
router.delete '/user/task/:id', auth, validateTask, (req, res) ->
taskIds = req.user.get "#{req.task.type}Ids"
req.user.del "tasks.#{req.task.id}"
# Remove one id from array of typeIds
req.user.remove "#{req.task.type}Ids", taskIds.indexOf(req.task.id), 1
deleteTask req.user, req.task.type, req.task.id
res.send 204
###
@ -297,15 +306,10 @@ scoreTask = (req, res, next) ->
addTask user, task
# TODO - could modify batchTxn to conform to this better
uObj = req.user.get()
tObj = uObj.tasks[taskId]
paths = {}
delta = algos.score(uObj, tObj, direction, {paths})
_.each paths, (v,k) -> user.set(k,helpers.dotGet(k, uObj));true
result = uObj.stats
result.delta = delta
res.json result
delta = score model, user, taskId, direction, ->
result = user.get('stats')
result.delta = delta
res.json result
###
POST /user/tasks/:taskId/:direction
@ -316,3 +320,8 @@ router.post '/user/tasks/:taskId/:direction', auth, scoreTask
module.exports = router
module.exports.auth = auth
module.exports.scoreTask = scoreTask # export so deprecated can call it
module.exports.NO_TOKEN_OR_UID = NO_TOKEN_OR_UID
module.exports.NO_USER_FOUND = NO_USER_FOUND
module.exports.addTask = addTask
module.exports.score = score
module.exports.deleteTask = deleteTask

View file

@ -1,6 +1,6 @@
express = require 'express'
router = new express.Router()
util = require('util')
util = require 'util'
_ = require 'lodash'
algos = require 'habitrpg-shared/script/algos'
@ -9,11 +9,9 @@ validator = require 'derby-auth/node_modules/validator'
check = validator.check
sanitize = validator.sanitize
misc = require '../app/misc'
api = require './api'
NO_TOKEN_OR_UID = err: "You must include a token and uid (user id) in your request"
NO_USER_FOUND = err: "No user found."
# ---------- /api/v1 API ------------
# ---------- /api/v2 API ------------
# Every url added beneath router is prefaced by /api/v2
###
@ -22,40 +20,74 @@ NO_USER_FOUND = err: "No user found."
router.get '/status', (req, res) ->
res.json status: 'up'
###
beforeEach auth interceptor
###
auth = (req, res, next) ->
uid = req.headers['x-api-user']
token = req.headers['x-api-key']
return res.json 401, NO_TOKEN_OR_UID unless uid || token
model = req.getModel()
query = model.query('users').withIdAndToken(uid, token)
query.fetch (err, user) ->
return res.json err: err if err
req.user = user
req.userObj = user.get()
return res.json 401, NO_USER_FOUND if !req.userObj || _.isEmpty(req.userObj)
req._isServer = true
next()
###
POST new actions
###
router.post '/', auth, (req, res) ->
router.post '/', api.auth, (req, res, next) ->
model = req.getModel()
{user} = req
actions = req.body
doneCount = 1 + # cron
_.size(actions) # standard operations
done = (err) ->
return next(err) if err
if --doneCount is 0
uObj = misc.hydrate user.get()
#transform user structure FROM user.tasks{} + user.habitIds[] TO user.habits[] + user.todos[] etc.
_.each ['habit','daily','todo','reward'], (type) ->
uObj["#{type}s"] = _.transform uObj["#{type}Ids"], (result, tid) -> result.push(uObj.tasks[tid])
delete uObj["#{type}Ids"]
delete uObj.tasks
res.json 200, uObj
console.log "Reply sent"
notEmpty = _.find actions, ((action) -> !_.isEmpty(action))
unless notEmpty
# yan's strange User.log({}) thing
doneCount = 1
return done()
misc.batchTxn model, (uObj, paths) ->
# habitrpg-shared/algos requires uObj.habits, uObj.dailys etc instead of uObj.tasks
_.each ['habit','daily','todo','reward'], (type) -> uObj["#{type}s"] = _.where(uObj.tasks, {type}); true
algos.cron uObj, {paths}
, {user, done, cron:true}
if _.isArray actions
actions.forEach (action)->
task = action.task ? {}
switch action.op
when score
{}
when newTask
req.user.set "tasks.#{req.task.id}", action.task
when "score"
sendScore = -> api.score(model, user, task.id, action.dir, done)
if task.type in ["daily","todo"]
# switch completed state. Since checkbox is not binded to model unlike when you click through Derby website.
completed = if action.dir is "up" then true else false
user.set "tasks.#{task.id}.completed", completed, sendScore
else sendScore()
console.log util.inspect req.body
when "sortTask"
path = action.task.type + "Ids"
a = user.get(path)
a.splice(action.to, 0, a.splice(action.from, 1)[0])
user.set path, a, done
res.json 200, req.userObj
when "addTask"
api.addTask user, task, done
when "delTask"
api.deleteTask user, task, done
# this API is only working with string or number variables. It should return error if object given or object is at the path.
when "set"
oldValue = user.get(action.path)
if _.isObject(action.value) or _.isObject(oldValue)
console.error "action.value was an object, which isn't currently supported. Tyler - double check this"
else
user.set action.path, action.value, done
else done()
module.exports = router