don't need public/private paths after all, can check path requests in store accessControl callbacks

This commit is contained in:
Tyler Renelle
2013-02-04 22:35:07 -05:00
parent 6966f6a439
commit 9723f3c37a
10 changed files with 186 additions and 188 deletions

View File

@@ -52,42 +52,40 @@ db.users.find().forEach(function(user){
// Note 'public' and 'private' are reserved words
var newUser = {
auth: user.auth, // we need this top-level due to derby-auth
pub:{
party: null,
invitations: [],
items: {
armor: user.items.armor || 0,
weapon: user.items.weapon || 0
},
stats: {
gp: user.stats.money || 0,
hp: user.stats.hp || 50,
exp: user.stats.exp || 0,
lvl: user.stats.lvl || 1
},
preferences: {
armorSet: user.preferences.armorSet || 'v1',
gender: user.preferences.gender || 'm'
}
apiToken: user.preferences.api_token || null, // set on update, we need derby.uuid()
preferences: {
armorSet: user.preferences.armorSet || 'v1',
gender: user.preferences.gender || 'm'
},
priv: {
balance: user.balance || 2,
lastCron: user.lastCron || +new Date,
tasks: user.tasks || {},
history: user.history || [],
apiToken: user.preferences.api_token || null, // set on update, we need derby.uuid()
idLists: {
habit:user.habitList || [],
daily:user.dailyList || [],
todo:user.todoList || [],
reward:user.rewardList || []
},
flags: {
partyEnabled: false,
itemsEnabled: user.items.itemsEnabled || false,
kickstarter: user.notifications.kickstarter || 'show',
ads: user.flags.ads || null // null because it's set on registration
}
balance: user.balance || 2,
lastCron: user.lastCron || +new Date,
history: user.history || [],
stats: {
gp: user.stats.money || 0,
hp: user.stats.hp || 50,
exp: user.stats.exp || 0,
lvl: user.stats.lvl || 1
},
items: {
armor: user.items.armor || 0,
weapon: user.items.weapon || 0
},
tasks: user.tasks || {},
idLists: {
habit: user.habitIds || [],
daily: user.dailyIds || [],
todo: user.todoIds || [],
reward: user.rewardIds || []
},
flags: {
partyEnabled: false,
itemsEnabled: user.items.itemsEnabled || false,
kickstarter: user.notifications.kickstarter || 'show',
ads: user.flags.ads || null // null because it's set on registration
},
party: {
current: null,
invitation: null
}
};

View File

@@ -85,7 +85,7 @@ module.exports.setupGrowlNotifications = (model) ->
statsNotification = (html, type) ->
#don't show notifications if user dead
return if user.get('pub.stats.lvl') == 0
return if user.get('stats.lvl') == 0
$.bootstrapGrowl html,
type: type # (null, 'info', 'error', 'success')
top_offset: 20
@@ -95,7 +95,7 @@ module.exports.setupGrowlNotifications = (model) ->
allow_dismiss: true
stackup_spacing: 10 # spacing between consecutive stacecked growls.
user.on 'set', 'priv.flags.itemsEnabled', (captures, args) ->
user.on 'set', 'flags.itemsEnabled', (captures, args) ->
return unless captures == true
message = "Congratulations, you have unlocked the Item Store! You can now buy weapons, armor, potions, etc. Read each item's comment for more information."
$('ul.items').popover
@@ -109,7 +109,7 @@ module.exports.setupGrowlNotifications = (model) ->
</div>"
$('ul.items').popover 'show'
user.on 'set', 'priv.flags.partyEnabled', (captures, args) ->
user.on 'set', 'flags.partyEnabled', (captures, args) ->
return unless captures == true
message = "Congratulations, you have unlocked the Party System! You can now group with your friends by adding their User Ids."
$('#add-party-button').popover
@@ -125,13 +125,13 @@ module.exports.setupGrowlNotifications = (model) ->
# Setup listeners which trigger notifications
user.on 'set', 'pub.stats.hp', (captures, args) ->
user.on 'set', 'stats.hp', (captures, args) ->
num = captures - args
rounded = Math.abs(num.toFixed(1))
if num < 0
statsNotification "<i class='icon-heart'></i>HP -#{rounded}", 'error' # lost hp from purchase
user.on 'set', 'pub.stats.gp', (captures, args) ->
user.on 'set', 'stats.gp', (captures, args) ->
num = captures - args
rounded = Math.abs(num.toFixed(1))
# made purchase
@@ -143,6 +143,6 @@ module.exports.setupGrowlNotifications = (model) ->
num = Math.abs(num)
statsNotification "<i class='icon-star'></i>Exp,GP +#{rounded}", 'success'
user.on 'set', 'pub.stats.lvl', (captures, args) ->
user.on 'set', 'stats.lvl', (captures, args) ->
if captures > args
statsNotification('<i class="icon-chevron-up"></i> Level Up!', 'info')

View File

@@ -57,9 +57,9 @@ module.exports.viewHelpers = (view) ->
return gp/0.25
view.fn 'currentArmor', (user) ->
user = { pub:{ items: {armor:0}, preferences: {gender:'m', armorSet:'v1'}}} unless user?
armor = user.pub.items.armor
{gender, armorSet} = user.pub.items
user = { items: {armor:0}, preferences: {gender:'m', armorSet:'v1'}} unless user?
armor = user.items.armor
{gender, armorSet} = user.preferences
if gender == 'f'
str = "armor#{armor}_f"
if parseInt(armor) > 1

View File

@@ -16,10 +16,10 @@ _ = require('underscore')
setupListReferences = (model) ->
taskTypes = ['habit', 'daily', 'todo', 'reward']
_.each taskTypes, (type) -> model.refList "_#{type}List", "_user.priv.tasks", "_user.priv.idLists.#{type}"
_.each taskTypes, (type) -> model.refList "_#{type}List", "_user.tasks", "_user.idLists.#{type}"
setupModelFns = (model) ->
model.fn '_tnl', '_user.pub.stats.lvl', (lvl) ->
model.fn '_tnl', '_user.stats.lvl', (lvl) ->
# see https://github.com/lefnire/habitrpg/issues/4
# also update in scoring.coffee. TODO create a function accessible in both locations
(lvl*100)/5
@@ -51,8 +51,8 @@ get '/', (page, model, next) ->
# Setup Item Store
_view.items =
armor: content.items.armor[parseInt(obj.pub.items?.armor || 0) + 1]
weapon: content.items.weapon[parseInt(obj.pub.items?.weapon || 0) + 1]
armor: content.items.armor[parseInt(obj.items?.armor || 0) + 1]
weapon: content.items.weapon[parseInt(obj.items?.weapon || 0) + 1]
potion: content.items.potion
reroll: content.items.reroll
@@ -65,8 +65,8 @@ get '/', (page, model, next) ->
setupModelFns(model)
# Subscribe to friends
if !_.isEmpty(obj.pub.party)
model.subscribe model.query('users').party(obj.pub.party), (err, party) ->
if !_.isEmpty(obj.party)
model.subscribe model.query('users').party(obj.party), (err, party) ->
model.ref '_party', party
page.render()
@@ -83,8 +83,8 @@ ready (model) ->
scoring.setModel(model)
#set cron immediately
lastCron = user.get('priv.lastCron')
user.set('priv.lastCron', +new Date) if (!lastCron? or lastCron == 'new')
lastCron = user.get('lastCron')
user.set('lastCron', +new Date) if (!lastCron? or lastCron == 'new')
# Setup model in scoring functions
scoring.cron(resetDom)
@@ -98,7 +98,7 @@ ready (model) ->
require('../server/private').app(exports, model)
user.on 'set', 'priv.tasks.*.completed', (i, completed, previous, isLocal, passed) ->
user.on 'set', 'tasks.*.completed', (i, completed, previous, isLocal, passed) ->
return if passed? && passed.cron # Don't do this stuff on cron
direction = () ->
return 'up' if completed==true and previous == false
@@ -106,7 +106,7 @@ ready (model) ->
throw new Error("Direction neither 'up' nor 'down' on checkbox set.")
# Score the user based on todo task
task = user.at("priv.tasks.#{i}")
task = user.at("tasks.#{i}")
scoring.score(i, direction())
exports.addTask = (e, el, next) ->
@@ -145,10 +145,10 @@ ready (model) ->
id = $(e.target).parents('li.task').attr('data-id')
return unless id?
task = user.at "priv.tasks.#{id}"
task = user.at "tasks.#{id}"
type = task.get('type')
history = task.get('priv.history')
history = task.get('history')
if history and history.length>2
# prevent delete-and-recreate hack on red tasks
if task.get('value') < 0
@@ -168,22 +168,22 @@ ready (model) ->
# fix when query subscriptions implemented properly
$('[rel=tooltip]').tooltip('hide')
ids = user.get("priv.idLists.#{type}")
ids = user.get("idLists.#{type}")
ids.splice(ids.indexOf(id),1)
user.del('priv.tasks.'+id)
user.set("priv.idLists.#{type}", ids)
user.del('tasks.'+id)
user.set("idLists.#{type}", ids)
exports.clearCompleted = (e, el) ->
todoIds = user.get('priv.idLists.todo')
todoIds = user.get('idLists.todo')
removed = false
_.each model.get('_todoList'), (task) ->
if task.completed
removed = true
user.del('priv.tasks.'+task.id)
user.del('tasks.'+task.id)
todoIds.splice(todoIds.indexOf(task.id), 1)
if removed
user.set('priv.idLists.todo', todoIds)
user.set('idLists.todo', todoIds)
exports.toggleDay = (e, el) ->
task = model.at(e.target)
@@ -226,22 +226,22 @@ ready (model) ->
#TODO: this should be working but it's not. so instead, i'm passing all needed values as data-attrs
# item = model.at(e.target)
gp = user.get 'pub.stats.gp'
gp = user.get 'stats.gp'
[type, value, index] = [ $(el).attr('data-type'), $(el).attr('data-value'), $(el).attr('data-index') ]
return if gp < value
user.set 'pub.stats.gp', gp - value
user.set 'stats.gp', gp - value
if type == 'armor'
user.set 'pub.items.armor', index
user.set 'items.armor', index
model.set '_view.items.armor', content.items.armor[parseInt(index) + 1]
else if type == 'weapon'
user.set 'pub.items.weapon', index
user.set 'items.weapon', index
model.set '_view.items.weapon', content.items.weapon[parseInt(index) + 1]
else if type == 'potion'
hp = user.get 'pub.stats.hp'
hp = user.get 'stats.hp'
hp += 15
hp = 50 if hp > 50
user.set 'pub.stats.hp', hp
user.set 'stats.hp', hp
exports.score = (e, el, next) ->
direction = $(el).attr('data-direction')
@@ -252,14 +252,14 @@ ready (model) ->
revive = (batch) ->
# Reset stats
batch.set 'pub.stats.hp', 50
batch.set 'pub.stats.lvl', 1
batch.set 'pub.stats.gp', 0
batch.set 'pub.stats.exp', 0
batch.set 'stats.hp', 50
batch.set 'stats.lvl', 1
batch.set 'stats.gp', 0
batch.set 'stats.exp', 0
# Reset items
batch.set 'pub.items.armor', 0
batch.set 'pub.items.weapon', 0
batch.set 'items.armor', 0
batch.set 'items.weapon', 0
# Reset item store
model.set '_view.items.armor', content.items.armor[1]
@@ -275,33 +275,33 @@ ready (model) ->
batch = new schema.BatchUpdate(model)
batch.startTransaction()
taskTypes = ['habit', 'daily', 'todo', 'reward']
batch.set 'priv.tasks', {}
_.each taskTypes, (type) -> batch.set "priv.idLists.#{type}", []
batch.set 'priv.balance', 2 if user.get('priv.balance') < 2 #only if they haven't manually bought tokens
batch.set 'tasks', {}
_.each taskTypes, (type) -> batch.set "idLists.#{type}", []
batch.set 'balance', 2 if user.get('balance') < 2 #only if they haven't manually bought tokens
revive(batch, true)
batch.commit()
resetDom(model)
exports.closeKickstarterNofitication = (e, el) ->
user.set('priv.flags.kickstarter', 'hide')
user.set('flags.kickstarter', 'hide')
exports.setMale = -> user.set('pub.preferences.gender', 'm')
exports.setFemale = -> user.set('pub.preferences.gender', 'f')
exports.setArmorsetV1 = -> user.set('pub.preferences.armorSet', 'v1')
exports.setArmorsetV2 = -> user.set('pub.preferences.armorSet', 'v2')
exports.setMale = -> user.set('preferences.gender', 'm')
exports.setFemale = -> user.set('preferences.gender', 'f')
exports.setArmorsetV1 = -> user.set('preferences.armorSet', 'v1')
exports.setArmorsetV2 = -> user.set('preferences.armorSet', 'v2')
exports.addParty = ->
id = model.get('_newPartyMember').replace(/[\s"]/g, '')
debugger
return if _.isEmpty(id)
if user.get('pub.party').indexOf(id) != -1
if user.get('party').indexOf(id) != -1
model.set "_view.addPartyError", "#{id} already in party."
return
query = model.query('users').party([id])
model.fetch query, (err, users) ->
partyMember = users.at(0).get()
if partyMember?.id?
user.push('pub.party', id)
user.push('party', id)
$('#add-party-modal').modal('hide')
window.location.reload() #TODO break old subscription, setup new subscript, remove this reload
model.set '_newPartyMember', ''
@@ -310,6 +310,6 @@ ready (model) ->
exports.emulateNextDay = ->
yesterday = +moment().subtract('days', 1).toDate()
user.set 'priv.lastCron', yesterday
user.set 'lastCron', yesterday
window.location.reload()

View File

@@ -6,62 +6,62 @@ derby = require 'derby'
userSchema =
# _id
pub:
stats: { gp: 0, exp: 0, lvl: 1, hp: 50 }
party: null
invitations: []
items: { armor: 0, weapon: 0 }
preferences: { gender: 'm', armorSet: 'v1' }
priv:
idLists:
habit: []
daily: []
todo: []
reward: []
apiToken: null # set in newUserObject below
lastCron: 'new' #this will be replaced with `+new Date` on first run
balance: 2
tasks: {}
flags:
partyEnabled: false
itemsEnabled: false
kickstarter: 'show'
# ads: 'show' # added on registration
stats: { gp: 0, exp: 0, lvl: 1, hp: 50 }
party: {
current: null
invitation: null
}
items: { armor: 0, weapon: 0 }
preferences: { gender: 'm', armorSet: 'v1' }
idLists:
habit: []
daily: []
todo: []
reward: []
apiToken: null # set in newUserObject below
lastCron: 'new' #this will be replaced with `+new Date` on first run
balance: 2
tasks: {}
flags:
partyEnabled: false
itemsEnabled: false
kickstarter: 'show'
# ads: 'show' # added on registration
module.exports.newUserObject = ->
# deep clone, else further new users get duplicate objects
newUser = lodash.cloneDeep userSchema
newUser.priv.apiToken = derby.uuid()
newUser.apiToken = derby.uuid()
for task in content.defaultTasks
guid = task.id = derby.uuid()
newUser.priv.tasks[guid] = task
newUser.tasks[guid] = task
switch task.type
when 'habit' then newUser.priv.idLists.habit.push guid
when 'daily' then newUser.priv.idLists.daily.push guid
when 'todo' then newUser.priv.idLists.todo.push guid
when 'reward' then newUser.priv.idLists.reward.push guid
when 'habit' then newUser.idLists.habit.push guid
when 'daily' then newUser.idLists.daily.push guid
when 'todo' then newUser.idLists.todo.push guid
when 'reward' then newUser.idLists.reward.push guid
return newUser
module.exports.updateUser = (batch) ->
user = batch.user
obj = batch.obj()
batch.set('priv.apiToken', derby.uuid()) unless obj.priv.apiToken
batch.set('apiToken', derby.uuid()) unless obj.apiToken
## Task List Cleanup
# FIXME temporary hack to fix lists (Need to figure out why these are happening)
tasks = obj.priv.tasks
tasks = obj.tasks
_.each ['habit','daily','todo','reward'], (type) ->
# 1. remove duplicates
# 2. restore missing zombie tasks back into list
taskIds = _.pluck( _.where(tasks, {type:type}), 'id')
union = _.union obj.priv.idLists[type], taskIds
union = _.union obj.idLists[type], taskIds
# 2. remove empty (grey) tasks
preened = _.filter(union, (val) -> _.contains(taskIds, val))
# There were indeed issues found, set the new list
batch.set("priv.idLists.#{type}", preened) # if _.difference(preened, userObj[path]).length != 0
batch.set("idLists.#{type}", preened) # if _.difference(preened, userObj[path]).length != 0
module.exports.BatchUpdate = BatchUpdate = (model) ->
user = model.at("_user")
@@ -100,9 +100,9 @@ module.exports.BatchUpdate = BatchUpdate = (model) ->
eg, user.set('stats', {hp:50, exp:10...}) will break dom bindings, but user.set('stats.hp',50) is ok
###
setStats: (stats) ->
stats ?= obj.pub.stats
stats ?= obj.stats
that = @
_.each Object.keys(stats), (key) -> that.set "pub.stats.#{key}", stats[key]
_.each Object.keys(stats), (key) -> that.set "stats.#{key}", stats[key]
# queue: (path, val) ->
# # Special function for setting object properties by string dot-notation. See http://stackoverflow.com/a/6394168/362790

View File

@@ -20,8 +20,8 @@ setModel = (m) ->
{modifiers} may manually pass in stats as {weapon, exp}. This is used for testing
###
expModifier = (value, modifiers = {}) ->
weapon = modifiers.weapon || user.get('pub.items.weapon')
lvl = modifiers.lvl || user.get('pub.stats.lvl')
weapon = modifiers.weapon || user.get('items.weapon')
lvl = modifiers.lvl || user.get('stats.lvl')
dmg = weapon * MODIFIER # each new weapon increases exp gain
dmg += (lvl-1) * MODIFIER # same for lvls
modified = value + (value * dmg)
@@ -33,8 +33,8 @@ expModifier = (value, modifiers = {}) ->
{modifiers} may manually pass in modifier as {armor, lvl}. This is used for testing
###
hpModifier = (value, modifiers = {}) ->
armor = modifiers.armor || user.get('pub.items.armor')
lvl = modifiers.lvl || user.get('pub.stats.lvl')
armor = modifiers.armor || user.get('items.armor')
lvl = modifiers.lvl || user.get('stats.lvl')
ac = armor * MODIFIER # each new armor decreases HP loss
ac += (lvl-1) * MODIFIER # same for lvls
modified = value - (value * ac)
@@ -62,37 +62,37 @@ updateStats = (newStats, batch) ->
obj = batch.obj()
# if user is dead, dont do anything
return if obj.pub.stats.lvl == 0
return if obj.stats.lvl == 0
if newStats.hp?
# Game Over
if newStats.hp <= 0
obj.pub.stats.lvl = 0 # signifies dead
obj.pub.stats.hp = 0
obj.stats.lvl = 0 # signifies dead
obj.stats.hp = 0
return
else
obj.pub.stats.hp = newStats.hp
obj.stats.hp = newStats.hp
if newStats.exp?
# level up & carry-over exp
tnl = model.get '_tnl'
if newStats.exp >= tnl
newStats.exp -= tnl
obj.pub.stats.lvl++
obj.pub.stats.hp = 50
if !obj.priv.flags.itemsEnabled and obj.pub.stats.lvl >= 2
obj.stats.lvl++
obj.stats.hp = 50
if !obj.flags.itemsEnabled and obj.stats.lvl >= 2
# Set to object, then also send to browser right away to get model.on() subscription notification
batch.set 'priv.flags.itemsEnabled', true
obj.priv.flags.itemsEnabled = true
if !obj.priv.flags.partyEnabled and obj.pub.stats.lvl >= 3
batch.set 'priv.flags.partyEnabled', true
obj.priv.flags.partyEnabled = true
obj.pub.stats.exp = newStats.exp
batch.set 'flags.itemsEnabled', true
obj.flags.itemsEnabled = true
if !obj.flags.partyEnabled and obj.stats.lvl >= 3
batch.set 'flags.partyEnabled', true
obj.flags.partyEnabled = true
obj.stats.exp = newStats.exp
if newStats.gp?
#FIXME what was I doing here? I can't remember, gp isn't defined
gp = 0.0 if (!gp? or gp<0)
obj.pub.stats.gp = newStats.gp
obj.stats.gp = newStats.gp
# {taskId} task you want to score
# {direction} 'up' or 'down'
@@ -106,10 +106,10 @@ score = (taskId, direction, times, batch, cron) ->
batch.startTransaction()
obj = batch.obj()
{gp, hp, exp, lvl} = obj.pub.stats
{gp, hp, exp, lvl} = obj.stats
taskPath = "priv.tasks.#{taskId}"
taskObj = obj.priv.tasks[taskId]
taskPath = "tasks.#{taskId}"
taskObj = obj.tasks[taskId]
{type, value} = taskObj
delta = 0
@@ -171,12 +171,12 @@ score = (taskId, direction, times, batch, cron) ->
taskObj.value = value
batch.set "#{taskPath}.value", taskObj.value
origStats = _.clone obj.pub.stats
origStats = _.clone obj.stats
updateStats {hp: hp, exp: exp, gp: gp}, batch
if commit
# newStats / origStats is a glorious hack to trick Derby into seeing the change in model.on(*)
newStats = _.clone batch.obj().pub.stats
_.each Object.keys(origStats), (key) -> obj.pub.stats[key] = origStats[key]
newStats = _.clone batch.obj().stats
_.each Object.keys(origStats), (key) -> obj.stats[key] = origStats[key]
batch.setStats(newStats)
# batch.setStats()
batch.commit()
@@ -192,12 +192,12 @@ cron = (resetDom_cb) ->
if daysPassed > 0
batch = new schema.BatchUpdate(model)
batch.startTransaction()
batch.set 'priv.lastCron', today
batch.set 'lastCron', today
obj = batch.obj()
hpBefore = obj.pub.stats.hp #we'll use this later so we can animate hp loss
hpBefore = obj.stats.hp #we'll use this later so we can animate hp loss
# Tally each task
todoTally = 0
_.each obj.priv.tasks, (taskObj) ->
_.each obj.tasks, (taskObj) ->
unless taskObj.id?
console.error "a task had a null id during cron, this should not be happening"
return
@@ -222,31 +222,31 @@ cron = (resetDom_cb) ->
if type == 'daily'
taskObj.history ?= []
taskObj.history.push { date: +new Date, value: value }
batch.set "priv.tasks.#{taskObj.id}.history", taskObj.history
batch.set "priv.tasks.#{taskObj.id}.completed", false
batch.set "tasks.#{taskObj.id}.history", taskObj.history
batch.set "tasks.#{taskObj.id}.completed", false
else
value = obj.priv.tasks[taskObj.id].value #get updated value
value = obj.tasks[taskObj.id].value #get updated value
absVal = if (completed) then Math.abs(value) else value
todoTally += absVal
# Finished tallying
obj.priv.history ?= {}; obj.priv.history.todos ?= []; obj.priv.history.exp ?= []
obj.priv.history.todos.push { date: today, value: todoTally }
obj.history ?= {}; obj.history.todos ?= []; obj.history.exp ?= []
obj.history.todos.push { date: today, value: todoTally }
# tally experience
expTally = obj.pub.stats.exp
expTally = obj.stats.exp
lvl = 0 #iterator
while lvl < (obj.pub.stats.lvl-1)
while lvl < (obj.stats.lvl-1)
lvl++
expTally += (lvl*100)/5
obj.priv.history.exp.push { date: today, value: expTally }
obj.history.exp.push { date: today, value: expTally }
# Set the new user specs, and animate HP loss
[hpAfter, obj.pub.stats.hp] = [obj.pub.stats.hp, hpBefore]
[hpAfter, obj.stats.hp] = [obj.stats.hp, hpBefore]
batch.setStats()
batch.set('history', obj.priv.history)
batch.set('history', obj.history)
batch.commit()
resetDom_cb(model)
setTimeout (-> user.set 'pub.stats.hp', hpAfter), 1000 # animate hp loss
setTimeout (-> user.set 'stats.hp', hpAfter), 1000 # animate hp loss
module.exports = {

View File

@@ -31,8 +31,8 @@ module.exports.deleteStaleAccounts = ->
collection.findEach un_registered, (err, user) ->
throw err if err
return unless user? #why does this happen sometimes?
if !!user.priv.lastCron # for now ignore missing crons, still looking into why this is happening
lastCron = new Date(user.priv.lastCron)
if !!user.lastCron # for now ignore missing crons, still looking into why this is happening
lastCron = new Date(user.lastCron)
diff = Math.abs(moment(today).sod().diff(moment(lastCron).sod(), "days"))
if diff > 10
removeAccount(collection, user._id)

View File

@@ -35,8 +35,8 @@ module.exports.app = (appExports, model) ->
appExports.buyReroll = (e, el, next) ->
batch = new schema.BatchUpdate(model)
obj = model.get('_user')
batch.set 'priv.balance', obj.priv.balance-1
_.each obj.priv.tasks, (task) -> batch.set("priv.tasks.#{task.id}.value", 0) unless task.type == 'reward'
batch.set 'balance', obj.balance-1
_.each obj.tasks, (task) -> batch.set("tasks.#{task.id}.value", 0) unless task.type == 'reward'
batch.commit()
module.exports.routes = (expressApp) ->
@@ -53,8 +53,8 @@ module.exports.routes = (expressApp) ->
userId = model.session.userId
model.fetch "users.#{userId}", (err, user) ->
model.ref '_user', "users.#{userId}"
model.set('_user.priv.balance', model.get('_user.priv.balance')+5)
model.set('_user.priv.flags.ads','hide')
model.set('_user.balance', model.get('_user.balance')+5)
model.set('_user.flags.ads','hide')
return res.send(200)
api_key = process.env.STRIPE_API_KEY # secret stripe API key

View File

@@ -49,8 +49,8 @@ module.exports = (expressApp, root, derby) ->
# Create task if doesn't exist
# TODO add service & icon to task
unless model.get("_user.priv.tasks.#{taskId}")
model.refList "_habitList", "_user.priv.tasks", "_user.priv.idLists.habit"
unless model.get("_user.tasks.#{taskId}")
model.refList "_habitList", "_user.tasks", "_user.idLists.habit"
model.at('_habitList').push {
id: taskId
type: 'habit'

View File

@@ -14,28 +14,28 @@
<pre class=prettyprint>{_user.id}</pre>
<h6>API Token</h6>
<pre class=prettyprint>{_user.priv.apiToken}</pre>
<pre class=prettyprint>{_user.apiToken}</pre>
<hr/>
<h4>Gender</h4>
<label class="radio">
<input type="radio" name="genderRadios" value="m" x-bind="click:setMale" checked="{equal(_user.pub.preferences.gender,'m')}">
<input type="radio" name="genderRadios" value="m" x-bind="click:setMale" checked="{equal(_user.preferences.gender,'m')}">
Male
</label>
<label class="radio">
<input type="radio" name="genderRadios" value="f" x-bind="click:setFemale" checked="{equal(_user.pub.preferences.gender,'f')}">
<input type="radio" name="genderRadios" value="f" x-bind="click:setFemale" checked="{equal(_user.preferences.gender,'f')}">
Female
</label>
{#if equal(_user.pub.preferences.gender,'f')}
{#if equal(_user.preferences.gender,'f')}
<h4>Armor Set</h4>
<label class="radio">
<input type="radio" name="armorSet" value="v1" x-bind="click:setArmorsetV1" checked="{equal(_user.pub.preferences.armorSet,'v1')}">
<input type="radio" name="armorSet" value="v1" x-bind="click:setArmorsetV1" checked="{equal(_user.preferences.armorSet,'v1')}">
v1
</label>
<label class="radio">
<input type="radio" name="armorSet" value="v2" x-bind="click:setArmorsetV2" checked="{equal(_user.pub.preferences.armorSet,'v2')}">
<input type="radio" name="armorSet" value="v2" x-bind="click:setArmorsetV2" checked="{equal(_user.preferences.armorSet,'v2')}">
v2
</label>
{/}
@@ -79,7 +79,7 @@
</app:myModal>
{/}
<!-- Game Over Modal -->
<div style="{#unless equal(_user.pub.stats.lvl,0)}display:none;{/}">
<div style="{#unless equal(_user.stats.lvl,0)}display:none;{/}">
<app:myModal noDismiss=true modalId='dead-modal'>
<table>
<tr>
@@ -100,7 +100,7 @@
<app:userTokens/>
<p>Highly discouraged because red tasks provide good incentive to improve (<a target="_blank" href="https://github.com/lefnire/habitrpg#all-my-tasks-are-red-im-dying-too-fast">read more</a>). However, this becomes necessary after long bouts of bad habits.</p>
<@footer>
{#if lessThan(_user.priv.balance,1)}
{#if lessThan(_user.balance,1)}
<a data-dismiss="modal" x-bind="click:showStripe" class="btn btn-danger btn-large">Buy More Tokens</a><span class='token-cost'>Not enough tokens</span>
{else}
<a data-dismiss="modal" x-bind=click:buyReroll class="btn btn-danger btn-large">Re-Roll</a><span class='token-cost'>4 Tokens</span>
@@ -125,7 +125,7 @@
</ul>
{/}
{#if equal(_user.priv.flags.kickstarter,'show')}
{#if equal(_user.flags.kickstarter,'show')}
<div class='alert alert-success'>
<a x-bind="click:closeKickstarterNofitication" class='pull-right'>Dismiss</a>
Help Habit by backing the <strong><a href="http://kck.st/XoA3Yg">Kickstarter</a></strong>! Funds iPhone & Android apps, <a href="https://github.com/lefnire/habitrpg/issues?labels=critical&page=1&state=open">bug fixes</a>, and the <a href="https://github.com/lefnire/habitrpg/issues/58">Groups feature</a>.
@@ -165,39 +165,39 @@
<!-- Avatar -->
<td class="avatar main-avatar">
<div class='avatar-sprites'>
<img class='weapon weapon-{_user.pub.items.weapon}' src="/img/BrowserQuest/habitrpg_mods/weapon{_user.pub.items.weapon}.png" />
<img class='armor armor-{_user.pub.items.armor}' src="/img/BrowserQuest/habitrpg_mods/{currentArmor(_user)}" />
<img class='weapon weapon-{_user.items.weapon}' src="/img/BrowserQuest/habitrpg_mods/weapon{_user.items.weapon}.png" />
<img class='armor armor-{_user.items.armor}' src="/img/BrowserQuest/habitrpg_mods/{currentArmor(_user)}" />
</div>
<div id="lvl"><span class="badge badge-info">Lvl {_user.pub.stats.lvl}</span></div>
<div id="lvl"><span class="badge badge-info">Lvl {_user.stats.lvl}</span></div>
</td>
<!-- Progress Bars -->
<td id="bars" style="width:{#if _party}70%{else}90%{/};">
<div class="progress progress-danger" rel=tooltip data-placement=bottom title="Health">
<div class="bar" style="width: {percent(_user.pub.stats.hp, 50)}%;"></div>
<span class="progress-text"><i class=icon-heart></i> {round(_user.pub.stats.hp)} / 50</span>
<div class="bar" style="width: {percent(_user.stats.hp, 50)}%;"></div>
<span class="progress-text"><i class=icon-heart></i> {round(_user.stats.hp)} / 50</span>
</div>
<div class="progress progress-warning" rel=tooltip data-placement=bottom title="Experience">
<div class="bar" style="width: {percent(_user.pub.stats.exp,_tnl)}%;"></div>
<div class="bar" style="width: {percent(_user.stats.exp,_tnl)}%;"></div>
<span class="progress-text">
{#if _user.history.exp}
<a x-bind=click:toggleChart data-toggle-id="exp-chart" data-history-path="_user.history.exp" rel=tooltip title="Progress"><i class=icon-signal></i></a>&nbsp;
{/}
<i class=icon-star></i> {round(_user.pub.stats.exp)} / {_tnl}
<i class=icon-star></i> {round(_user.stats.exp)} / {_tnl}
</span>
</div>
</td>
<!-- Party -->
{#if _user.priv.flags.partyEnabled}
{#if _user.flags.partyEnabled}
{#each _party as :member}
<td class="avatar party-avatar" rel="tooltip" title="{username(:member.auth)}" data-placement="bottom" >
<div class='avatar-sprites'>
<img class='weapon weapon-{:member.pub.items.weapon}' src="/img/BrowserQuest/habitrpg_mods/weapon{:member.pub.items.weapon}.png" />
<img class='armor armor-{:member.pub.items.armor}' src="/img/BrowserQuest/habitrpg_mods/{currentArmor(:member)}" />
<img class='weapon weapon-{:member.items.weapon}' src="/img/BrowserQuest/habitrpg_mods/weapon{:member.items.weapon}.png" />
<img class='armor armor-{:member.items.armor}' src="/img/BrowserQuest/habitrpg_mods/{currentArmor(:member)}" />
</div>
<div id="lvl"><span class="badge badge-info">Lvl {:member.pub.stats.lvl}</span></div>
<div id="lvl"><span class="badge badge-info">Lvl {:member.stats.lvl}</span></div>
</td>
{/}
<td><a class="btn" id="add-party-button" data-target="#add-party-modal" data-toggle="modal"><i class="icon-user"></i></a></td>
@@ -281,7 +281,7 @@
<!--Title -->
<div class="row-fluid">
<div class="span6"><h2>Rewards</h2></div>
<div class="span6" id="money">{gold(_user.pub.stats.money)} <img src='/img/coin_single_gold.png'/> {silver(_user.pub.stats.money)} <img src='/img/coin_single_silver.png'/></div>
<div class="span6" id="money">{gold(_user.stats.money)} <img src='/img/coin_single_gold.png'/> {silver(_user.stats.money)} <img src='/img/coin_single_silver.png'/></div>
</div>
<!-- Content -->
@@ -289,7 +289,7 @@
{#each _rewardList as :task}<app:task />{/}
</ul>
{#if _user.priv.flags.itemsEnabled}
{#if _user.flags.itemsEnabled}
<ul class='items'>
{#with _view.items.armor as :item}<app:item />{/}
{#with _view.items.weapon as :item}<app:item />{/}
@@ -346,12 +346,12 @@
<userTokens:>
<div class="pull-right">
<div class="input-append">
<span class="uneditable-input" style="width:auto;">{tokens(_user.priv.balance)}</span>
<span class="uneditable-input" style="width:auto;">{tokens(_user.balance)}</span>
<span class="add-on">Tokens</span>
</div>
<a class="label" data-toggle="modal" href='#reset-modal'><i class="icon-ban-circle"></i>Reset</a>
</div>
<!--<span class="well pull-right">Tokens: {tokens(_user.priv.balance)}</span>-->
<!--<span class="well pull-right">Tokens: {tokens(_user.balance)}</span>-->
<newTask: nonvoid>
<form class="form-inline new-task-form" id=new-{{@type}} data-task-type={{@type}} x-bind=submit:addTask>