mirror of
https://github.com/sudoxnym/habitica-self-host.git
synced 2026-08-02 04:00:36 +00:00
apiv2 - much cleaned up, by re-using fucntions in api.coffee. misc.batchTxn takes an optional user param, in case we don't want to use private paths "_user" (which we don't want to do on the server!)
This commit is contained in:
parent
4655b2fbc2
commit
b88c2ad1a3
3 changed files with 71 additions and 70 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -12,10 +12,23 @@ utils = require 'derby-auth/utils'
|
|||
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.push "#{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, cb}
|
||||
delta
|
||||
|
||||
# ---------- /api/v1 API ------------
|
||||
# Every url added beneath router is prefaced by /api/v1
|
||||
|
|
@ -202,12 +215,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 user, req.task.type, req.task.id
|
||||
res.send 204
|
||||
|
||||
###
|
||||
|
|
@ -297,15 +305,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, req.user, taskId, direction, ->
|
||||
result = user.get('stats')
|
||||
result.delta = delta
|
||||
res.json result
|
||||
|
||||
###
|
||||
POST /user/tasks/:taskId/:direction
|
||||
|
|
@ -318,3 +321,6 @@ 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
|
||||
|
|
|
|||
|
|
@ -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'
|
||||
|
|
@ -23,71 +23,65 @@ router.get '/status', (req, res) ->
|
|||
###
|
||||
POST new actions
|
||||
###
|
||||
router.post '/', api.auth, (req, res) ->
|
||||
router.post '/', api.auth, (req, res, next) ->
|
||||
model = req.getModel()
|
||||
user = req.user
|
||||
{user} = req
|
||||
actions = req.body
|
||||
console.log util.inspect req.body
|
||||
#console.log util.inspect req.body
|
||||
|
||||
doneCount = 0
|
||||
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"] = _.where(uObj.tasks, {type}); true
|
||||
delete uObj["#{type}Ids"]
|
||||
delete uObj.tasks
|
||||
res.json 200, uObj
|
||||
console.log "Reply sent"
|
||||
|
||||
misc.batchTxn model, (uObj, paths) ->
|
||||
# habitrpg-shared/algos requires uObj.habits, uObj.dailys etc instead of uObj.tasks
|
||||
doneCount++
|
||||
# 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}
|
||||
,{cron:true}
|
||||
|
||||
|
||||
_.each ['habit', 'daily', 'todo', 'reward'], (type) ->
|
||||
model.refList "_#{type}List", "_user.tasks", "_user.#{type}Ids"
|
||||
, {user, done, cron:true}
|
||||
|
||||
if _.isArray actions
|
||||
actions.forEach (action)->
|
||||
task = {}
|
||||
if action.task? then task = action.task
|
||||
doneCount++
|
||||
|
||||
if action.op == "score"
|
||||
if task.type == "daily" || task.type == "todo"
|
||||
# switch completed state. Since checkbox is not binded to model unlike when you click through Derby website.
|
||||
completed = if action.dir == "up" then true else false
|
||||
user.set("tasks.#{task.id}.completed", completed)
|
||||
misc.score(model, task.id, action.dir, true)
|
||||
task = action.task ? {}
|
||||
|
||||
if action.op == "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)
|
||||
switch action.op
|
||||
when "score"
|
||||
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, done
|
||||
doneCount++
|
||||
api.score model, user, task.id, action.dir, done
|
||||
|
||||
if action.op == "addTask"
|
||||
model.unshift "_#{task.type}List", task
|
||||
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)
|
||||
|
||||
if action.op == "delTask"
|
||||
# to make sure we update DOM on Derby client
|
||||
ids = user.get(task.type + 'Ids')
|
||||
ids.splice(ids.indexOf(task.id), 1);
|
||||
user.set(task.type + 'Ids', ids)
|
||||
when "addTask"
|
||||
api.addTask user, task, done
|
||||
|
||||
# Actually delete the task
|
||||
user.del ("tasks." + task.id)
|
||||
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.
|
||||
if action.op == "set"
|
||||
oldValue = user.get(action.path);
|
||||
if (typeof action.value == "number" || typeof action.value == "string")
|
||||
if (typeof oldValue == "number" || typeof oldValue == "string")
|
||||
user.set(action.path, action.value)
|
||||
|
||||
user = misc.hydrate user.get()
|
||||
|
||||
#transform user structure FROM user.tasks{} + user.habitIds[] TO user.habits[] + user.todos[] etc.
|
||||
["habit", "daily", "todo", "reward"].forEach (type) ->
|
||||
user[type + 's'] = []
|
||||
user[type + 'Ids'].forEach (id)->
|
||||
user[type + 's'].push(user.tasks[id])
|
||||
delete user[type + 'Ids']
|
||||
delete user.tasks
|
||||
res.json 200, user
|
||||
console.log "Reply sent"
|
||||
# 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
|
||||
|
||||
module.exports = router
|
||||
Loading…
Reference in a new issue