PageRenderTime 42ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/archive/derby_controllers/misc.coffee

https://github.com/ewingd/habitrpg
CoffeeScript | 152 lines | 114 code | 14 blank | 24 comment | 11 complexity | 931601ba07e4743afcc4fd8930698ebd MD5 | raw file
Possible License(s): CC-BY-SA-4.0
  1. _ = require 'lodash'
  2. algos = require 'habitrpg-shared/script/algos'
  3. items = require('habitrpg-shared/script/items').items
  4. helpers = require('habitrpg-shared/script/helpers')
  5. #TODO put this in habitrpg-shared
  6. ###
  7. We can't always use refLists, but we often still need to get a positional path by id: eg, users.1234.tasks.5678.value
  8. For arrays (which use indexes, not id-paths), here's a helper function so we can run indexedPath('users',:user.id,'tasks',:task.id,'value)
  9. ###
  10. indexedPath = ->
  11. _.reduce arguments, (m,v) =>
  12. return v if !m #first iteration
  13. return "#{m}.#{v}" if _.isString v #string paths
  14. return "#{m}." + _.findIndex(@model.get(m),v)
  15. , ''
  16. taskInChallenge = (task) ->
  17. return undefined unless task?.challenge
  18. @model.at indexedPath.call(@, "groups.#{task.group.id}.challenges", {id:task.challenge}, "#{task.type}s", {id:task.id})
  19. ###
  20. algos.score wrapper for habitrpg-helpers to work in Derby. We need to do model.set() instead of simply setting the
  21. object properties, and it's very difficult to diff the two objects and find dot-separated paths to set. So we to first
  22. clone our user object (if we don't do that, it screws with model.on() listeners, ping Tyler for an explaination),
  23. perform the updates while tracking paths, then all the values at those paths
  24. ###
  25. module.exports.score = (model, taskId, direction, allowUndo=false) ->
  26. drop = undefined
  27. delta = batchTxn model, (uObj, paths) ->
  28. tObj = uObj.tasks[taskId]
  29. # Stuff for undo
  30. if allowUndo
  31. tObjBefore = _.cloneDeep tObj
  32. tObjBefore.completed = !tObjBefore.completed if tObjBefore.type in ['daily', 'todo']
  33. previousUndo = model.get('_undo')
  34. clearTimeout(previousUndo.timeoutId) if previousUndo?.timeoutId
  35. timeoutId = setTimeout (-> model.del('_undo')), 20000
  36. model.set '_undo', {stats:_.cloneDeep(uObj.stats), task:tObjBefore, timeoutId: timeoutId}
  37. delta = algos.score(uObj, tObj, direction, {paths})
  38. model.set('_streakBonus', uObj._tmp.streakBonus) if uObj._tmp?.streakBonus
  39. drop = uObj._tmp?.drop
  40. # Update challenge statistics
  41. # FIXME put this in it's own batchTxn, make batchTxn model.at() ref aware (not just _user)
  42. # FIXME use reflists for users & challenges
  43. if (chalTask = taskInChallenge.call({model}, tObj)) and chalTask?.get()
  44. model._dontPersist = false
  45. chalTask.incr "value", delta
  46. chal = model.at indexedPath.call({model}, "groups.#{tObj.group.id}.challenges", {id:tObj.challenge})
  47. chalUser = -> indexedPath.call({model}, chal.path(), 'users', {id:uObj.id})
  48. cu = model.at chalUser()
  49. unless cu?.get()
  50. chal.push "users", {id: uObj.id, name: helpers.username(uObj.auth, uObj.profile?.name)}
  51. cu = model.at chalUser()
  52. else
  53. cu.set 'name', helpers.username(uObj.auth, uObj.profile?.name) # update their name incase it changed
  54. cu.set "#{tObj.type}s.#{tObj.id}",
  55. value: tObj.value
  56. history: tObj.history
  57. model._dontPersist = true
  58. , done:->
  59. if drop and $?
  60. model.set '_drop', drop
  61. $('#item-dropped-modal').modal 'show'
  62. delta
  63. ###
  64. Cleanup task-corruption (null tasks, rogue/invisible tasks, etc)
  65. Obviously none of this should be happening, but we'll stop-gap until we can find & fix
  66. Gotta love refLists! see https://github.com/lefnire/habitrpg/issues/803 & https://github.com/lefnire/habitrpg/issues/6343
  67. ###
  68. module.exports.fixCorruptUser = (model) ->
  69. user = model.at('_user')
  70. tasks = user.get('tasks')
  71. ## Remove corrupted tasks
  72. _.each tasks, (task, key) ->
  73. unless task?.id? and task?.type?
  74. user.del("tasks.#{key}")
  75. delete tasks[key]
  76. true
  77. resetDom = false
  78. batchTxn model, (uObj, paths, batch) ->
  79. ## fix https://github.com/lefnire/habitrpg/issues/1086
  80. uniqPets = _.uniq(uObj.items.pets)
  81. batch.set('items.pets', uniqPets) if !_.isEqual(uniqPets, uObj.items.pets)
  82. if uObj.invitations?.guilds
  83. uniqInvites = _.uniq(uObj.invitations.guilds)
  84. batch.set('invitations.guilds', uniqInvites) if !_.isEqual(uniqInvites, uObj.invitations.guilds)
  85. ## Task List Cleanup
  86. ['habit','daily','todo','reward'].forEach (type) ->
  87. # 1. remove duplicates
  88. # 2. restore missing zombie tasks back into list
  89. idList = uObj["#{type}Ids"]
  90. taskIds = _.pluck( _.where(tasks, {type}), 'id')
  91. union = _.union idList, taskIds
  92. # 2. remove empty (grey) tasks
  93. preened = _.filter union, (id) -> id and _.contains(taskIds, id)
  94. # There were indeed issues found, set the new list
  95. if !_.isEqual(idList, preened)
  96. batch.set("#{type}Ids", preened)
  97. console.error uObj.id + "'s #{type}s were corrupt."
  98. true
  99. resetDom = !_.isEmpty(paths)
  100. require('./browser').resetDom(model) if resetDom
  101. module.exports.viewHelpers = (view) ->
  102. #misc
  103. view.fn "percent", (x, y) ->
  104. x=1 if x==0
  105. Math.round(x/y*100)
  106. view.fn 'indexOf', (str1, str2) ->
  107. return false unless str1 && str2
  108. str1.indexOf(str2) != -1
  109. view.fn "round", Math.round
  110. view.fn "floor", Math.floor
  111. view.fn "ceil", Math.ceil
  112. view.fn "truarr", (num) -> num-1
  113. view.fn 'count', (arr) -> arr?.length or 0
  114. view.fn 'int',
  115. get: (num) -> num
  116. set: (num) -> [parseInt(num)]
  117. view.fn 'indexedPath', indexedPath
  118. #iCal
  119. view.fn "encodeiCalLink", helpers.encodeiCalLink
  120. #User
  121. view.fn "gems", (balance) -> balance * 4
  122. #Challenges
  123. view.fn 'taskInChallenge', (task) ->
  124. taskInChallenge.call(@,task)?.get()
  125. view.fn 'taskAttrFromChallenge', (task, attr) ->
  126. taskInChallenge.call(@,task)?.get(attr)
  127. view.fn 'brokenChallengeLink', (task) ->
  128. task?.challenge and !(taskInChallenge.call(@,task)?.get())
  129. view.fn 'challengeMemberScore', (member, tType, tid) ->
  130. Math.round(member["#{tType}s"]?[tid]?.value)