From b8968658654a5cfafee456a0c6e7505dd557370a Mon Sep 17 00:00:00 2001 From: Tyler Renelle Date: Wed, 30 Jan 2013 15:57:36 -0500 Subject: [PATCH 01/51] v1 api using api token --- src/server/serverRoutes.coffee | 34 ++++++++++++++++++---------------- src/server/store.coffee | 15 ++++++++++++++- views/app/index.html | 11 ++++++++--- 3 files changed, 40 insertions(+), 20 deletions(-) diff --git a/src/server/serverRoutes.coffee b/src/server/serverRoutes.coffee index 5b5235eba4..ba5fc05d7c 100644 --- a/src/server/serverRoutes.coffee +++ b/src/server/serverRoutes.coffee @@ -12,35 +12,37 @@ module.exports = (expressApp, root, derby) -> expressApp.get '/terms', (req, res) -> staticPages.render 'terms', res - # ---------- REST API ------------ + # ---------- Deprecated Paths ------------ - # Deprecated API (will remove soon) - deprecatedMessage = 'This REST resource is no longer supported, use /users/:uid/tasks/:taskId/:direction instead.' - expressApp.get '/:uid/up/:score?', (req, res) -> - res.send(200, deprecatedMessage) - expressApp.get '/:uid/down/:score?', (req, res) -> - res.send(200, deprecatedMessage) + deprecatedMessage = 'This API is no longer supported, see https://github.com/lefnire/habitrpg/wiki/API for new protocol' + expressApp.get '/:uid/up/:score?', (req, res) -> res.send(500, deprecatedMessage) + expressApp.get '/:uid/down/:score?', (req, res) -> res.send(500, deprecatedMessage) + expressApp.post '/v1/users/:uid/tasks/:taskId/:direction', (req, res) -> res.send(500, deprecatedMessage) - # New API - # test with `curl -X POST -H "Content-Type:application/json" localhost:3000/users/{uid}/tasks/productivity/up` - expressApp.post '/users/:uid/tasks/:taskId/:direction', (req, res) -> + # ---------- v1 API ------------ + + ### + v1 API. Requires user-id and api_token, task-id, direction. Test with: + curl -X POST -H "Content-Type:application/json" -d '{"api_token":"{TOKEN}"}' localhost:3000/v1/users/{UID}/tasks/productivity/up + ### + expressApp.post '/v1/users/:uid/tasks/:taskId/:direction', (req, res) -> {uid, taskId, direction} = req.params - {title, service, icon} = req.body + {api_token, title, service, icon} = req.body console.log {params:req.params, body:req.body} if process.env.NODE_ENV == 'development' # Send error responses for improper API call + return res.send(500, 'request body "api_token" required') unless api_token return res.send(500, ':uid required') unless uid return res.send(500, ':taskId required') unless taskId return res.send(500, ":direction must be 'up' or 'down'") unless direction in ['up','down'] model = req.getModel() - model.fetch "users.#{uid}", (err, user) -> + model.fetch model.query('users').withIdAndToken(uid, api_token), (err, result) -> return res.send(500, err) if err + user = result.at(0) userObj = user.get() - # Server crashes without this, I think some users are entering non-guid userIds and/or trying to use the API without having an account - unless userObj && !_.isEmpty(userObj.stats) - console.log {taskId:taskId, direction:direction, user:userObj, error: 'non-user attempted to score'} if process.env.NODE_ENV == 'development' - return res.send(500, "User #{uid} not found") + if _.isEmpty(userObj) + return res.send(500, "User with uid=#{uid}, token=#{api_token} not found. Make sure you're not using your username, but your User Id") model.ref('_user', user) diff --git a/src/server/store.coffee b/src/server/store.coffee index a7dedfaafb..8c786be279 100644 --- a/src/server/store.coffee +++ b/src/server/store.coffee @@ -14,4 +14,17 @@ module.exports = (store) -> return unless @session and @session.userId # https://github.com/codeparty/racer/issues/37 next = arguments[arguments.length - 1] isServer = not @req.socket - next(isServer) \ No newline at end of file + next(isServer) + + ### + Get user with API token + ### + store.query.expose "users", "withIdAndToken", (id, api_token) -> + @where("id").equals(id) + .where('preferences.api_token').equals(api_token) + .limit(1) + + store.queryAccess "users", "withIdAndToken", (id, token, next) -> + return next(false) unless @session and @session.userId # https://github.com/codeparty/racer/issues/37 + isServer = not @req.socket + next(isServer) diff --git a/views/app/index.html b/views/app/index.html index f9bd1f0309..82c0e7e7da 100644 --- a/views/app/index.html +++ b/views/app/index.html @@ -8,10 +8,15 @@ {#if _loggedIn} - User ID
- Copy this ID for use in third party applications. -
{_user.id}

+

API

+ Copy these for use in third party applications. +
User ID
+
{_user.id}
+
API Token
+
{_user.preferences.api_token}
+ +

Gender

+ + +
+ {#if _view.addFriendError} +
{_view.addFriendError}
+ {/} + + +
+
+ {else} Login / Register With Facebook @@ -150,6 +161,8 @@
+ + + + + + + + + +
@@ -157,6 +170,8 @@
Lvl {_user.stats.lvl}
@@ -173,7 +188,27 @@
+
    + {#each _view.friends} +
  • +
    + + +
    +
    Lvl {_user.stats.lvl}
    +
  • + + {/} +
+ +
From 519dcf256e85495e0732d64985d4ef2cae0415a8 Mon Sep 17 00:00:00 2001 From: Tyler Renelle Date: Wed, 30 Jan 2013 17:14:55 -0500 Subject: [PATCH 04/51] reactive model fucntion seems to bust the app, may need to send to use model.subscribe on get '/' and redirect on friend-add --- src/app/index.coffee | 10 +++++++--- src/app/schema.coffee | 3 +++ views/app/index.html | 10 +++------- 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/src/app/index.coffee b/src/app/index.coffee index a2754e6c04..d3c62e580c 100644 --- a/src/app/index.coffee +++ b/src/app/index.coffee @@ -34,9 +34,9 @@ setupModelFns = (model) -> else "armor#{armor}_m.png" - model.fn '_user._friends', '_user.friends', (friendIds) -> - model.subscribe model.query('users').friends(friendIds), (err, friends) -> - model.ref '_view.party', friends +# model.fn '_user._friends', '_user.friends', (friendIds) -> +# model.fetch model.query('users').friends(friendIds), (err, friends) -> +# model.set '_view.friends', friends # ========== ROUTES ========== @@ -79,6 +79,10 @@ get '/', (page, model, next) -> setupListReferences(model) setupModelFns(model) + if !_.isEmpty(userObj.friends) + model.subscribe model.query('users').friends(userObj.friends), (err, friends) -> + model.ref '_friends', friends + page.render() # ========== CONTROLLER FUNCTIONS ========== diff --git a/src/app/schema.coffee b/src/app/schema.coffee index f591bfee85..93837269fe 100644 --- a/src/app/schema.coffee +++ b/src/app/schema.coffee @@ -12,6 +12,7 @@ module.exports.newUserObject = -> items: { itemsEnabled: false, armor: 0, weapon: 0 } notifications: { kickstarter: 'show' } preferences: { gender: 'm', armorSet: 'v1' } + friends: [] tasks: {} habitIds: [] dailyIds: [] @@ -36,6 +37,8 @@ module.exports.updateUser = (user, userObj) -> _.defaults prefs, { gender: 'm', armorSet: 'v1', api_token: derby.uuid() } user.set 'preferences', prefs unless _.isEqual(prefs, userObj.preferences) + user.setNull 'friends', [] + ## Task List Cleanup # FIXME temporary hack to fix lists (Need to figure out why these are happening) # FIXME consolidate these all under user.listIds so we can set them en-masse diff --git a/views/app/index.html b/views/app/index.html index fdc6a0e079..2826e8808a 100644 --- a/views/app/index.html +++ b/views/app/index.html @@ -190,16 +190,12 @@ - +
    - {#each _view.friends} + {#each _friends as :friend}
  • -
    - - -
    -
    Lvl {_user.stats.lvl}
    + {:friend.id}
  • {/} From 7f9ef40251556aeafd997e8fc1fcbc686e7ccbf7 Mon Sep 17 00:00:00 2001 From: Tyler Renelle Date: Wed, 30 Jan 2013 17:29:35 -0500 Subject: [PATCH 05/51] trim uid entry --- src/app/index.coffee | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/app/index.coffee b/src/app/index.coffee index d3c62e580c..72686dfa9f 100644 --- a/src/app/index.coffee +++ b/src/app/index.coffee @@ -308,15 +308,18 @@ ready (model) -> exports.setArmorsetV2 = -> user.set('preferences.armorSet', 'v2') exports.addFriend = -> - friendId = model.get('_newFriend') - return if /^(\s)*$/.test(friendId) + friendId = model.get('_newFriend').replace(/[\s"]/g, '') + return if _.isEmpty(friendId) query = model.query('users').friends([friendId]) model.fetch query, (err, users) -> friend = users.get(0) - unless friend - model.set "_view.addFriendError", "User with id #{friendId} not found." - return - #TODO ensure unique - user.push('friends', friendId) - $('#add-friend-modal').modal('hide') - model.set '_newFriend', '' + if friend + #TODO ensure unique + #TODO trim, remove quotes + user.push('friends', friendId) + $('#add-friend-modal').modal('hide') + window.location.reload() #TODO break old subscript, setup new, then remove reload + model.set '_newFriend', '' + else + model.set "_view.addFriendError", "User with id #{friendId} not found." + return From fcadcb000f753d5c2f63b545df596870e8c5e98a Mon Sep 17 00:00:00 2001 From: Tyler Renelle Date: Wed, 30 Jan 2013 17:41:06 -0500 Subject: [PATCH 06/51] convert armor model.fn to a view.fn, so we can use on party too --- src/app/helpers.coffee | 14 +++++++++++++- src/app/index.coffee | 10 ---------- src/server/store.coffee | 2 +- views/app/index.html | 10 ++++++++-- 4 files changed, 22 insertions(+), 14 deletions(-) diff --git a/src/app/helpers.coffee b/src/app/helpers.coffee index da74ee35dc..8ab6bf2435 100644 --- a/src/app/helpers.coffee +++ b/src/app/helpers.coffee @@ -54,4 +54,16 @@ module.exports.viewHelpers = (view) -> a < b view.fn "tokens", (money) -> - return money/0.25 \ No newline at end of file + return money/0.25 + + view.fn 'currentArmor', (user) -> + console.log user + [gender, armor, armorSet] = [user.preferences.gender, user.items.armor, user.preferences.armorSet] + if gender == 'f' + str = "armor#{armor}_f" + if parseInt(armor) > 1 + armorSet = if armorSet then armorSet else 'v1' + str += '_' + armorSet + return "#{str}.png" + else + return "armor#{armor}_m.png" \ No newline at end of file diff --git a/src/app/index.coffee b/src/app/index.coffee index 72686dfa9f..8c9f9c78fb 100644 --- a/src/app/index.coffee +++ b/src/app/index.coffee @@ -24,16 +24,6 @@ setupModelFns = (model) -> # also update in scoring.coffee. TODO create a function accessible in both locations (lvl*100)/5 - model.fn '_user._armor', '_user.items.armor', '_user.preferences.armorSet', '_user.preferences.gender', (armor, armorSet, gender) -> - if gender == 'f' - str = "armor#{armor}_f" - if parseInt(armor) > 1 - armorSet = if armorSet then armorSet else 'v1' - str += '_' + armorSet - return "#{str}.png" - else - "armor#{armor}_m.png" - # model.fn '_user._friends', '_user.friends', (friendIds) -> # model.fetch model.query('users').friends(friendIds), (err, friends) -> # model.set '_view.friends', friends diff --git a/src/server/store.coffee b/src/server/store.coffee index 1b3d099551..9bb497854e 100644 --- a/src/server/store.coffee +++ b/src/server/store.coffee @@ -34,7 +34,7 @@ module.exports = (store) -> ### store.query.expose "users", "friends", (ids) -> @where("id").within(ids) - .only('stats', 'items', 'auth.local.username', 'auth.facebook.displayName') + .only('stats', 'preferences.gender', 'preferences.armorSet', 'items', 'auth.local.username', 'auth.facebook.displayName') store.queryAccess "users", "friends", (ids, next) -> next(true) # no harm in public user stats diff --git a/views/app/index.html b/views/app/index.html index 2826e8808a..a5927034c5 100644 --- a/views/app/index.html +++ b/views/app/index.html @@ -166,7 +166,7 @@
    - +
    Lvl {_user.stats.lvl}
    @@ -195,7 +195,13 @@
      {#each _friends as :friend}
    • - {:friend.id} +
      +
      + + +
      +
      Lvl {_user.stats.lvl}
      +
    • {/} From c4526b3a37d48d1b72beab0c050fecbf964b433d Mon Sep 17 00:00:00 2001 From: Tyler Renelle Date: Wed, 30 Jan 2013 17:49:21 -0500 Subject: [PATCH 07/51] fixes to html to include friend stuff --- styles/app/index.styl | 2 +- views/app/index.html | 27 ++++++++++----------------- 2 files changed, 11 insertions(+), 18 deletions(-) diff --git a/styles/app/index.styl b/styles/app/index.styl index 79a0db9fb2..e199ae29aa 100644 --- a/styles/app/index.styl +++ b/styles/app/index.styl @@ -117,7 +117,7 @@ li:hover .task-meta-controls .hover-show float:none margin:0px auto - td#avatar + td.avatar vertical-align: top text-align: center diff --git a/views/app/index.html b/views/app/index.html index a5927034c5..f9a3939aef 100644 --- a/views/app/index.html +++ b/views/app/index.html @@ -163,7 +163,7 @@ - +
      @@ -191,23 +191,16 @@ - -
        - {#each _friends as :friend} -
      • -
        -
        - - -
        -
        Lvl {_user.stats.lvl}
        + {#each _friends as :friend} + +
        + +
        -
      • - - {/} -
      - - +
      Lvl {:friend.stats.lvl}
      + + {/} + From 71650c8925b8c59a597fbc2e3ffe39fdfa158638 Mon Sep 17 00:00:00 2001 From: Tyler Renelle Date: Wed, 30 Jan 2013 17:52:45 -0500 Subject: [PATCH 08/51] don't console.log --- src/app/helpers.coffee | 1 - 1 file changed, 1 deletion(-) diff --git a/src/app/helpers.coffee b/src/app/helpers.coffee index 8ab6bf2435..3122d47096 100644 --- a/src/app/helpers.coffee +++ b/src/app/helpers.coffee @@ -57,7 +57,6 @@ module.exports.viewHelpers = (view) -> return money/0.25 view.fn 'currentArmor', (user) -> - console.log user [gender, armor, armorSet] = [user.preferences.gender, user.items.armor, user.preferences.armorSet] if gender == 'f' str = "armor#{armor}_f" From 55a019df1ccdb8a476a27b237ba7e245dfeb2721 Mon Sep 17 00:00:00 2001 From: Tyler Renelle Date: Wed, 30 Jan 2013 18:04:02 -0500 Subject: [PATCH 09/51] better friend validation --- src/app/index.coffee | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/app/index.coffee b/src/app/index.coffee index 8c9f9c78fb..144b7a9dda 100644 --- a/src/app/index.coffee +++ b/src/app/index.coffee @@ -300,16 +300,17 @@ ready (model) -> exports.addFriend = -> friendId = model.get('_newFriend').replace(/[\s"]/g, '') return if _.isEmpty(friendId) + if user.get('friends').indexOf(friendId) != -1 + model.set "_view.addFriendError", "#{friendId} already in party." + return query = model.query('users').friends([friendId]) model.fetch query, (err, users) -> friend = users.get(0) - if friend + if friend.id? #TODO ensure unique - #TODO trim, remove quotes user.push('friends', friendId) $('#add-friend-modal').modal('hide') window.location.reload() #TODO break old subscript, setup new, then remove reload model.set '_newFriend', '' else model.set "_view.addFriendError", "User with id #{friendId} not found." - return From e8ac4dcf867854428359c434201c028f7c73e95b Mon Sep 17 00:00:00 2001 From: Tyler Renelle Date: Wed, 30 Jan 2013 18:22:52 -0500 Subject: [PATCH 10/51] unlock the party system at level 3, view.fn 'userName' --- src/app/browser.coffee | 20 ++++++++++++++++++-- src/app/content.coffee | 3 --- src/app/helpers.coffee | 10 +++++++++- src/app/index.coffee | 4 ++-- src/app/schema.coffee | 1 + src/app/scoring.coffee | 4 +++- views/app/index.html | 11 ++++++----- 7 files changed, 39 insertions(+), 14 deletions(-) diff --git a/src/app/browser.coffee b/src/app/browser.coffee index e52e367bd6..0eb6c63767 100644 --- a/src/app/browser.coffee +++ b/src/app/browser.coffee @@ -97,17 +97,33 @@ module.exports.setupGrowlNotifications = (model) -> user.on 'set', 'items.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 - title: content.items.unlockedMessage.title + title: "Item Store Unlocked" placement: 'left' trigger: 'manual' html: true content: "
      - #{content.items.unlockedMessage.content} [Close] + #{message} [Close]
      " $('ul.items').popover 'show' + 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-friend-button').popover + title: "Pary System Unlocked" + placement: 'bottom' + trigger: 'manual' + html: true + content: "
      + + #{message} [Close] +
      " + $('#add-friend-button').popover 'show' + + # Setup listeners which trigger notifications user.on 'set', 'stats.hp', (captures, args) -> num = captures - args diff --git a/src/app/content.coffee b/src/app/content.coffee index 6750047ee1..00791b068e 100644 --- a/src/app/content.coffee +++ b/src/app/content.coffee @@ -55,9 +55,6 @@ module.exports = ] items: - unlockedMessage: - title: "Item Store Unlocked" - content: "Congratulations, you have unlocked the Item Store! You can now buy weapons, armor, potions, etc. Read each item's comment for more information." #TODO: figure out how to calculate index & type without having to store it in the JSON weapon: [ {type: 'weapon', index: 0, text: "Sword 1", icon: "item-sword1", notes:'Training weapon.', value:0} diff --git a/src/app/helpers.coffee b/src/app/helpers.coffee index 3122d47096..a287ed9b3b 100644 --- a/src/app/helpers.coffee +++ b/src/app/helpers.coffee @@ -65,4 +65,12 @@ module.exports.viewHelpers = (view) -> str += '_' + armorSet return "#{str}.png" else - return "armor#{armor}_m.png" \ No newline at end of file + return "armor#{armor}_m.png" + + view.fn "userName", (auth) -> + if auth?.facebook?.displayName? + auth.facebook.displayName + else if auth?.local? + auth.local.username + else + 'Anonymous' \ No newline at end of file diff --git a/src/app/index.coffee b/src/app/index.coffee index 144b7a9dda..3da1d42bc4 100644 --- a/src/app/index.coffee +++ b/src/app/index.coffee @@ -69,6 +69,7 @@ get '/', (page, model, next) -> setupListReferences(model) setupModelFns(model) + # Subscribe to friends if !_.isEmpty(userObj.friends) model.subscribe model.query('users').friends(userObj.friends), (err, friends) -> model.ref '_friends', friends @@ -307,10 +308,9 @@ ready (model) -> model.fetch query, (err, users) -> friend = users.get(0) if friend.id? - #TODO ensure unique user.push('friends', friendId) $('#add-friend-modal').modal('hide') - window.location.reload() #TODO break old subscript, setup new, then remove reload + window.location.reload() #TODO break old subscription, setup new subscript, remove this reload model.set '_newFriend', '' else model.set "_view.addFriendError", "User with id #{friendId} not found." diff --git a/src/app/schema.coffee b/src/app/schema.coffee index 93837269fe..1efdd0044c 100644 --- a/src/app/schema.coffee +++ b/src/app/schema.coffee @@ -12,6 +12,7 @@ module.exports.newUserObject = -> items: { itemsEnabled: false, armor: 0, weapon: 0 } notifications: { kickstarter: 'show' } preferences: { gender: 'm', armorSet: 'v1' } + flags: { partyEnabled: false } friends: [] tasks: {} habitIds: [] diff --git a/src/app/scoring.coffee b/src/app/scoring.coffee index c6f5dae618..4b7df92b2a 100644 --- a/src/app/scoring.coffee +++ b/src/app/scoring.coffee @@ -96,8 +96,10 @@ updateStats = (newStats, update) -> newStats.exp -= tnl userSet 'stats.lvl', userObj.stats.lvl + 1, update userSet 'stats.hp', 50, update - if !userObj.items?.itemsEnabled and newStats.exp >=15 + if !userObj.items?.itemsEnabled and newStats.lvl >= 2 user.set 'items.itemsEnabled', true #bit of trouble using userSet here + if !userObj.flags?.partyEnabled and newStats.lvl >= 3 + user.set 'flags.partyEnabled', true userSet 'stats.exp', newStats.exp, update if newStats.money? diff --git a/views/app/index.html b/views/app/index.html index f9a3939aef..6ea902659c 100644 --- a/views/app/index.html +++ b/views/app/index.html @@ -158,7 +158,7 @@
      -
      +
      @@ -190,17 +190,18 @@ - - {#each _friends as :friend} - + {/} + {/} - From a6ac1b0ce8e360800d6e6f695b1845b0f9e1e930 Mon Sep 17 00:00:00 2001 From: Tyler Renelle Date: Wed, 30 Jan 2013 18:57:46 -0500 Subject: [PATCH 11/51] view.fn on specific user paths, getting errors otherwise --- src/app/helpers.coffee | 3 +-- views/app/index.html | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/app/helpers.coffee b/src/app/helpers.coffee index a287ed9b3b..5a23a07f11 100644 --- a/src/app/helpers.coffee +++ b/src/app/helpers.coffee @@ -56,8 +56,7 @@ module.exports.viewHelpers = (view) -> view.fn "tokens", (money) -> return money/0.25 - view.fn 'currentArmor', (user) -> - [gender, armor, armorSet] = [user.preferences.gender, user.items.armor, user.preferences.armorSet] + view.fn 'currentArmor', (gender, armor, armorSet) -> if gender == 'f' str = "armor#{armor}_f" if parseInt(armor) > 1 diff --git a/views/app/index.html b/views/app/index.html index 6ea902659c..2c23c75686 100644 --- a/views/app/index.html +++ b/views/app/index.html @@ -166,7 +166,7 @@ @@ -195,7 +195,7 @@ From 03f2fc1e81d3201308a0b40416c6a8822686d075 Mon Sep 17 00:00:00 2001 From: Tyler Renelle Date: Wed, 30 Jan 2013 20:53:09 -0500 Subject: [PATCH 12/51] fix not updating on lvl up --- src/app/scoring.coffee | 1 + 1 file changed, 1 insertion(+) diff --git a/src/app/scoring.coffee b/src/app/scoring.coffee index 4b7df92b2a..66fa4ac288 100644 --- a/src/app/scoring.coffee +++ b/src/app/scoring.coffee @@ -96,6 +96,7 @@ updateStats = (newStats, update) -> newStats.exp -= tnl userSet 'stats.lvl', userObj.stats.lvl + 1, update userSet 'stats.hp', 50, update + newStats.lvl = userObj.stats.lvl if !userObj.items?.itemsEnabled and newStats.lvl >= 2 user.set 'items.itemsEnabled', true #bit of trouble using userSet here if !userObj.flags?.partyEnabled and newStats.lvl >= 3 From d2c5506234e399e824366c2c35e53806724f370f Mon Sep 17 00:00:00 2001 From: Tyler Renelle Date: Wed, 30 Jan 2013 20:54:34 -0500 Subject: [PATCH 13/51] show friend modal for non logged in user --- views/app/index.html | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/views/app/index.html b/views/app/index.html index 2c23c75686..7a419f7d6c 100644 --- a/views/app/index.html +++ b/views/app/index.html @@ -62,16 +62,6 @@ - -
      - {#if _view.addFriendError} -
      {_view.addFriendError}
      - {/} - - - -
      - {else} Login / Register With Facebook @@ -118,6 +108,16 @@ + +
      + {#if _view.addFriendError} +
      {_view.addFriendError}
      + {/} + + + +
      + {#if _flash.error}
        From 7a478ab6cd3d9680dba35a399beff083b8c31d99 Mon Sep 17 00:00:00 2001 From: Tyler Renelle Date: Wed, 30 Jan 2013 21:22:38 -0500 Subject: [PATCH 14/51] fix to username, apply to main user --- src/app/helpers.coffee | 5 ++++- src/app/index.coffee | 6 ------ views/app/index.html | 4 ++-- 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/src/app/helpers.coffee b/src/app/helpers.coffee index 5a23a07f11..1429b50168 100644 --- a/src/app/helpers.coffee +++ b/src/app/helpers.coffee @@ -66,9 +66,12 @@ module.exports.viewHelpers = (view) -> else return "armor#{armor}_m.png" - view.fn "userName", (auth) -> + view.fn "username", (auth) -> if auth?.facebook?.displayName? auth.facebook.displayName + else if auth?.facebook? + fb = auth.facebook + if fb._raw then "#{fb.name.givenName} #{fb.name.familyName}" else fb.name else if auth?.local? auth.local.username else diff --git a/src/app/index.coffee b/src/app/index.coffee index 3da1d42bc4..3d9848e39d 100644 --- a/src/app/index.coffee +++ b/src/app/index.coffee @@ -49,12 +49,6 @@ get '/', (page, model, next) -> return page.redirect '/500.html' unless userObj? #this should never happen, but it is. Looking into it - # support legacy Everyauth schema (now using derby-auth, Passport) - if username = userObj.auth?.local?.username - _view.loginName = username - else if fb = userObj.auth?.facebook - _view.loginName = if fb._raw then "#{fb.name.givenName} #{fb.name.familyName}" else fb.name - # Setup Item Store items = userObj.items _view.items = diff --git a/views/app/index.html b/views/app/index.html index 7a419f7d6c..f2491e88ba 100644 --- a/views/app/index.html +++ b/views/app/index.html @@ -142,7 +142,7 @@ Login / Register {else}
        - + @@ -192,7 +192,7 @@ {#if _user.flags.partyEnabled} {#each _friends as :friend} -
      + {#if _user.flags.partyEnabled} + {#each _friends as :friend} +
      Lvl {:friend.stats.lvl}
      - +
      Lvl {_user.stats.lvl}
      - +
      Lvl {:friend.stats.lvl}
      +
      From 6b0a443fc247a8e9cb777e5223b2e97955e8d06d Mon Sep 17 00:00:00 2001 From: Tyler Renelle Date: Wed, 30 Jan 2013 21:22:49 -0500 Subject: [PATCH 15/51] add migration for adding missing preferences (to be run) --- migrations/20130129_add_missing_preferences.js | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 migrations/20130129_add_missing_preferences.js diff --git a/migrations/20130129_add_missing_preferences.js b/migrations/20130129_add_missing_preferences.js new file mode 100644 index 0000000000..6b0dd92210 --- /dev/null +++ b/migrations/20130129_add_missing_preferences.js @@ -0,0 +1,5 @@ +db.users.update( + {'preferences':{$exists:false}}, + {$set:{preferences:{gender:'m'}}}, + {multi:true} +) \ No newline at end of file From 7952cc71a1f231b8829287dd2524f749bca9f252 Mon Sep 17 00:00:00 2001 From: Tyler Renelle Date: Wed, 30 Jan 2013 21:27:37 -0500 Subject: [PATCH 16/51] typo --- src/app/index.coffee | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/app/index.coffee b/src/app/index.coffee index 3d9848e39d..f7d5ebaf67 100644 --- a/src/app/index.coffee +++ b/src/app/index.coffee @@ -300,7 +300,8 @@ ready (model) -> return query = model.query('users').friends([friendId]) model.fetch query, (err, users) -> - friend = users.get(0) + friend = users.at(0).get() + debugger if friend.id? user.push('friends', friendId) $('#add-friend-modal').modal('hide') From 6adc5dab402cc7a9e29fca4d260bfe88d2bceb3f Mon Sep 17 00:00:00 2001 From: Tyler Renelle Date: Wed, 30 Jan 2013 21:31:03 -0500 Subject: [PATCH 17/51] better check on friend exists --- src/app/index.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/index.coffee b/src/app/index.coffee index f7d5ebaf67..b0d660c08d 100644 --- a/src/app/index.coffee +++ b/src/app/index.coffee @@ -302,7 +302,7 @@ ready (model) -> model.fetch query, (err, users) -> friend = users.at(0).get() debugger - if friend.id? + if friend?.id? user.push('friends', friendId) $('#add-friend-modal').modal('hide') window.location.reload() #TODO break old subscription, setup new subscript, remove this reload From 9708b80bdc6807ad80f6dfcbafe930d5ef40f7cd Mon Sep 17 00:00:00 2001 From: Zachary Kain Date: Wed, 30 Jan 2013 22:24:29 -0500 Subject: [PATCH 18/51] minor layout changes to give party avatars some breathing room :) --- styles/app/index.styl | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/styles/app/index.styl b/styles/app/index.styl index e199ae29aa..5ffb9dfa96 100644 --- a/styles/app/index.styl +++ b/styles/app/index.styl @@ -117,6 +117,9 @@ li:hover .task-meta-controls .hover-show float:none margin:0px auto + td + padding-right: 2em + td.avatar vertical-align: top text-align: center @@ -136,10 +139,9 @@ li:hover .task-meta-controls .hover-show .weapon-6 left:-20px td#bars - padding: 10px 0 0 10px + padding-top: 10px #bars - width: 100% .progress position: relative height: 25px From 791a19893c9db1b5e08df324c44feda4996d269a Mon Sep 17 00:00:00 2001 From: Zachary Kain Date: Wed, 30 Jan 2013 22:25:20 -0500 Subject: [PATCH 19/51] change the logic dictating change in bar size from if parties enabled to having party members --- views/app/index.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/views/app/index.html b/views/app/index.html index f2491e88ba..8ef73b5b3d 100644 --- a/views/app/index.html +++ b/views/app/index.html @@ -158,7 +158,7 @@
      -
      +
      @@ -172,7 +172,7 @@ -
      +
      {round(_user.stats.hp)} / 50 From c3f6dd3c7cbb693c7fe79a41b44f00cfa974f998 Mon Sep 17 00:00:00 2001 From: Tyler Renelle Date: Thu, 31 Jan 2013 07:39:20 -0500 Subject: [PATCH 20/51] add armorSet to prefs migration --- migrations/20130129_add_missing_preferences.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/migrations/20130129_add_missing_preferences.js b/migrations/20130129_add_missing_preferences.js index 6b0dd92210..745a365bd0 100644 --- a/migrations/20130129_add_missing_preferences.js +++ b/migrations/20130129_add_missing_preferences.js @@ -1,5 +1,5 @@ db.users.update( {'preferences':{$exists:false}}, - {$set:{preferences:{gender:'m'}}}, + {$set:{preferences:{gender: 'm', armorSet: 'v1'}}}, {multi:true} -) \ No newline at end of file +) From 642b63f2007e0b927a09247a9ab9627248f538ea Mon Sep 17 00:00:00 2001 From: Tyler Renelle Date: Thu, 31 Jan 2013 23:54:21 -0500 Subject: [PATCH 21/51] add BatchUpdate class, apply to page load --- src/app/index.coffee | 3 ++- src/app/schema.coffee | 31 +++++++++++++++++++++++++------ 2 files changed, 27 insertions(+), 7 deletions(-) diff --git a/src/app/index.coffee b/src/app/index.coffee index b0d660c08d..15885fbbe9 100644 --- a/src/app/index.coffee +++ b/src/app/index.coffee @@ -59,7 +59,7 @@ get '/', (page, model, next) -> model.set '_view', _view - schema.updateUser(user, userObj) + schema.updateUser(model, userObj) setupListReferences(model) setupModelFns(model) @@ -309,3 +309,4 @@ ready (model) -> model.set '_newFriend', '' else model.set "_view.addFriendError", "User with id #{friendId} not found." + diff --git a/src/app/schema.coffee b/src/app/schema.coffee index 68d08611fb..260ed0ecfb 100644 --- a/src/app/schema.coffee +++ b/src/app/schema.coffee @@ -29,16 +29,18 @@ module.exports.newUserObject = -> when 'reward' then newUser.rewardIds.push guid return newUser -module.exports.updateUser = (user, userObj) -> - user.set 'notifications.kickstarter', 'show' unless userObj.notifications?.kickstarter? +module.exports.updateUser = (model, userObj) -> + user = model.at('_user') + batch = new BatchUpdate(model) + + batch.queue('notifications.kickstarter', 'show') unless userObj.notifications?.kickstarter? + batch.queue('friends', []) unless !_.isEmpty(userObj.friends) # Preferences, including API key # Some side-stepping to avoid unecessary set (one day, model.update... one day..) prefs = _.clone(userObj.preferences) _.defaults prefs, { gender: 'm', armorSet: 'v1', api_token: derby.uuid() } - user.set 'preferences', prefs unless _.isEqual(prefs, userObj.preferences) - - user.setNull 'friends', [] + batch.queue('preferences', prefs) unless _.isEqual(prefs, userObj.preferences) ## Task List Cleanup # FIXME temporary hack to fix lists (Need to figure out why these are happening) @@ -57,4 +59,21 @@ module.exports.updateUser = (user, userObj) -> # There were indeed issues found, set the new list # TODO _.difference might still be empty for duplicates in one list? - user.set(path, preened) if _.difference(preened, userObj[path]).length != 0 + batch.queue(path, preened) if _.difference(preened, userObj[path]).length != 0 + +module.exports.BatchUpdate = BatchUpdate = (model) -> + user = model.at('_user') + updates = {} + { + queue: (path, val) -> + commit = model._commit + model._commit = (txn) -> + txn.isPrivate = true + commit.apply(this, arguments) + user.set(path, val) + model._commit = commit + updates[path] = val + + commit: -> + user.set "update__", updates # some hackery in our own branched racer-db-mongo, see findAndModify + } From 96984a29fb30d18668af9a7008c9aca253be4fb9 Mon Sep 17 00:00:00 2001 From: Tyler Renelle Date: Fri, 1 Feb 2013 00:02:19 -0500 Subject: [PATCH 22/51] batchupdate for cron --- src/app/scoring.coffee | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/app/scoring.coffee b/src/app/scoring.coffee index 66fa4ac288..26f937b554 100644 --- a/src/app/scoring.coffee +++ b/src/app/scoring.coffee @@ -4,7 +4,8 @@ _ = require 'underscore' content = require './content' helpers = require './helpers' browser = require './browser' -MODIFIER = .03 # each new level, armor, weapon add 3% modifier (this number may change) +schema = require './schema' +MODIFIER = .03 # each new level, armor, weapon add 3% modifier (this number may change) user = undefined model = undefined @@ -188,6 +189,7 @@ cron = (resetDom_cb) -> if daysPassed > 0 user.set 'lastCron', today userObj = user.get() + batch = new schema.BatchUpdate(model) hpBefore = userObj.stats.hp #we'll use this later so we can animate hp loss # Tally each task todoTally = 0 @@ -219,7 +221,7 @@ cron = (resetDom_cb) -> else absVal = if (completed) then Math.abs(value) else value todoTally += absVal - user.set 'tasks.' + taskObj.id, taskObj + batch.queue('tasks.' + taskObj.id, taskObj) # Finished tallying userObj.history ?= {}; userObj.history.todos ?= []; userObj.history.exp ?= [] @@ -234,8 +236,9 @@ cron = (resetDom_cb) -> # Set the new user specs, and animate HP loss [hpAfter, userObj.stats.hp] = [userObj.stats.hp, hpBefore] - user.set 'stats', userObj.stats - user.set 'history', userObj.history + batch.queue('stats', userObj.stats) + batch.queue('history', userObj.history) + batch.commit() resetDom_cb(model) setTimeout (-> user.set 'stats.hp', hpAfter), 1000 # animate hp loss From 1350f74c78401a44b9dceb6646c90fc446a5df10 Mon Sep 17 00:00:00 2001 From: Tyler Renelle Date: Fri, 1 Feb 2013 00:08:51 -0500 Subject: [PATCH 23/51] apply batch update to reset & revive --- src/app/index.coffee | 38 ++++++++++++++++---------------------- 1 file changed, 16 insertions(+), 22 deletions(-) diff --git a/src/app/index.coffee b/src/app/index.coffee index 15885fbbe9..741e276e73 100644 --- a/src/app/index.coffee +++ b/src/app/index.coffee @@ -249,40 +249,34 @@ ready (model) -> task = model.at $(el).parents('li')[0] scoring.score(task.get('id'), direction) - revive = (userObj, animateHp = false) -> + revive = (batch) -> # Reset stats - userObj.stats.hp = 50 unless animateHp # if we're animating hp-reset, we'll set to 50 ourselves later in our functions - userObj.stats.lvl = 1; userObj.stats.money = 0; userObj.stats.exp = 0 + batch.queue 'stats.hp', 50 + batch.queue 'stats.lvl', 1 + batch.queue 'stats.money', 0 + batch.queue 'stats.exp', 0 # Reset items - userObj.items.armor = 0; userObj.items.weapon = 0 + batch.queue 'items.armor', 0 + batch.queue 'items.weapon', 0 # Reset item store model.set '_view.items.armor', content.items.armor[1] model.set '_view.items.weapon', content.items.weapon[1] exports.revive = (e, el) -> - userObj = user.get() - revive(userObj, true) - - user.set 'stats', userObj.stats - user.set 'items', userObj.items - # Re-render (since we replaced objects en-masse, see https://github.com/lefnire/habitrpg/issues/80) - resetDom(model) - setTimeout (-> user.set 'stats.hp', 50), 0 # animate hp loss + batch = new schema.BatchUpdate(model) + revive(batch) + batch.commit() exports.reset = (e, el) -> - userObj = user.get() + batch = new schema.BatchUpdate(model) taskTypes = ['habit', 'daily', 'todo', 'reward'] - userObj.tasks = {} - _.each taskTypes, (type) -> userObj["#{type}Ids"] = [] - userObj.balance = 2 if userObj.balance < 2 #only if they haven't manually bought tokens - revive(userObj, true) - - # Set new user - model.set "users.#{userObj.id}", userObj - resetDom(model) - setTimeout (-> user.set 'stats.hp', 50), 0 # animate hp loss + batch.queue 'tasks', {} + _.each taskTypes, (type) -> batch.queue "#{type}Ids", [] + batch.queue 'balance', 2 if user.get('balance') < 2 #only if they haven't manually bought tokens + revive(batch, true) + batch.commit() exports.closeKickstarterNofitication = (e, el) -> user.set('notifications.kickstarter', 'hide') From ecaf8643a46695d8f94935c12605a547f26f6b34 Mon Sep 17 00:00:00 2001 From: Tyler Renelle Date: Fri, 1 Feb 2013 00:39:42 -0500 Subject: [PATCH 24/51] batch update for general scoring. note, model.on * broken --- src/app/index.coffee | 7 ++++-- src/app/schema.coffee | 22 ++++++++++++++--- src/app/scoring.coffee | 54 ++++++++++++++++-------------------------- 3 files changed, 45 insertions(+), 38 deletions(-) diff --git a/src/app/index.coffee b/src/app/index.coffee index 741e276e73..158b1fe342 100644 --- a/src/app/index.coffee +++ b/src/app/index.coffee @@ -45,7 +45,8 @@ get '/', (page, model, next) -> model.subscribe q, (err, user) -> #user = result.at(0) model.ref '_user', user - userObj = user.get() + batch = new schema.BatchUpdate(model) + userObj = batch.getUser() return page.redirect '/500.html' unless userObj? #this should never happen, but it is. Looking into it @@ -59,7 +60,9 @@ get '/', (page, model, next) -> model.set '_view', _view - schema.updateUser(model, userObj) + schema.updateUser(batch) + batch.commit() + setupListReferences(model) setupModelFns(model) diff --git a/src/app/schema.coffee b/src/app/schema.coffee index 260ed0ecfb..480a337d26 100644 --- a/src/app/schema.coffee +++ b/src/app/schema.coffee @@ -29,9 +29,8 @@ module.exports.newUserObject = -> when 'reward' then newUser.rewardIds.push guid return newUser -module.exports.updateUser = (model, userObj) -> - user = model.at('_user') - batch = new BatchUpdate(model) +module.exports.updateUser = (batch) -> + userObj = batch.getUser() batch.queue('notifications.kickstarter', 'show') unless userObj.notifications?.kickstarter? batch.queue('friends', []) unless !_.isEmpty(userObj.friends) @@ -63,6 +62,7 @@ module.exports.updateUser = (model, userObj) -> module.exports.BatchUpdate = BatchUpdate = (model) -> user = model.at('_user') + userObj = undefined updates = {} { queue: (path, val) -> @@ -74,6 +74,22 @@ module.exports.BatchUpdate = BatchUpdate = (model) -> model._commit = commit updates[path] = val + getUser: -> userObj ?= user.get() + + ### + Handles updating the user model. If this is an en-mass operation (eg, server cron), pass the user object as {update}. + otherwise, null means commit the changes immediately + ### + updateAndQueue: (path, val) -> + # Special function for setting object properties by string dot-notation. See http://stackoverflow.com/a/6394168/362790 + arr = path.split('.') + arr.reduce (curr, next, index) -> + if (arr.length - 1) == index + curr[next] = val + curr[next] + , @getUser() + @queue path, val + commit: -> user.set "update__", updates # some hackery in our own branched racer-db-mongo, see findAndModify } diff --git a/src/app/scoring.coffee b/src/app/scoring.coffee index 26f937b554..d9a7611e9b 100644 --- a/src/app/scoring.coffee +++ b/src/app/scoring.coffee @@ -53,30 +53,13 @@ taskDeltaFormula = (currentValue, direction) -> delta = if (currentValue < 0) then (( -0.1 * currentValue + 1 ) * sign) else (( Math.pow(0.9,currentValue) ) * sign) return delta - -### - Handles updating the user model. If this is an en-mass operation (eg, server cron), pass the user object as {update}. - otherwise, null means commit the changes immediately -### -userSet = (path, value, update) -> - if update - # Special function for setting object properties by string dot-notation. See http://stackoverflow.com/a/6394168/362790 - arr = path.split('.') - arr.reduce (curr, next, index) -> - if (arr.length - 1) == index - curr[next] = value - curr[next] - , update - else - user.set path, value - ### Updates user stats with new stats. Handles death, leveling up, etc {stats} new stats {update} if aggregated changes, pass in userObj as update. otherwise commits will be made immediately ### -updateStats = (newStats, update) -> - userObj = update || user.get() +updateStats = (newStats, batch) -> + userObj = batch.getUser() # if user is dead, dont do anything return if userObj.stats.lvl == 0 @@ -84,38 +67,42 @@ updateStats = (newStats, update) -> if newStats.hp? # Game Over if newStats.hp <= 0 - userSet 'stats.lvl', 0, update # signifies dead - userSet 'stats.hp', 0, update + batch.updateAndQueue 'stats.lvl', 0 # signifies dead + batch.updateAndQueue 'stats.hp', 0 return else - userSet 'stats.hp', newStats.hp, update + batch.updateAndQueue 'stats.hp', newStats.hp if newStats.exp? # level up & carry-over exp tnl = user.get '_tnl' if newStats.exp >= tnl newStats.exp -= tnl - userSet 'stats.lvl', userObj.stats.lvl + 1, update - userSet 'stats.hp', 50, update + batch.updateAndQueue 'stats.lvl', userObj.stats.lvl + 1 + batch.updateAndQueue 'stats.hp', 50 newStats.lvl = userObj.stats.lvl if !userObj.items?.itemsEnabled and newStats.lvl >= 2 - user.set 'items.itemsEnabled', true #bit of trouble using userSet here + batch.queue 'items.itemsEnabled', true #bit of trouble using userSet here if !userObj.flags?.partyEnabled and newStats.lvl >= 3 - user.set 'flags.partyEnabled', true - userSet 'stats.exp', newStats.exp, update + batch.queue 'flags.partyEnabled', true + batch.updateAndQueue 'stats.exp', newStats.exp if newStats.money? money = 0.0 if (!money? or money<0) - userSet 'stats.money', newStats.money, update + batch.updateAndQueue 'stats.money', newStats.money # {taskId} task you want to score # {direction} 'up' or 'down' # {times} # times to call score on this task (1 unless cron, usually) # {update} if we're running updates en-mass (eg, cron on server) pass in userObj -score = (taskId, direction, times, update) -> +score = (taskId, direction, times, batch) -> times ?= 1 - userObj = update or user.get() + commit = !batch? + console.log {commit:commit} + batch ?= new schema.BatchUpdate(model) + userObj = batch.getUser() + {money, hp, exp, lvl} = userObj.stats taskPath = "tasks.#{taskId}" @@ -175,8 +162,9 @@ score = (taskId, direction, times, update) -> hp += money # hp - money difference money = 0 - userSet "#{taskPath}.value", value, update - updateStats {hp: hp, exp: exp, money: money}, update + batch.updateAndQueue "#{taskPath}.value", value + updateStats {hp: hp, exp: exp, money: money}, batch + batch.commit() if commit return delta ### @@ -188,8 +176,8 @@ cron = (resetDom_cb) -> daysPassed = helpers.daysBetween(today, user.get('lastCron')) if daysPassed > 0 user.set 'lastCron', today - userObj = user.get() batch = new schema.BatchUpdate(model) + userObj = batch.getUser() hpBefore = userObj.stats.hp #we'll use this later so we can animate hp loss # Tally each task todoTally = 0 From cb85c676232b4d12620fa49c6b527ba19e38ad07 Mon Sep 17 00:00:00 2001 From: Tyler Renelle Date: Fri, 1 Feb 2013 11:17:02 -0500 Subject: [PATCH 25/51] almost working, but not double event-listeners and not propagating to other browsers. need more than just override model._commit --- package.json | 2 +- src/app/schema.coffee | 23 +++++++++++++---------- src/app/scoring.coffee | 7 ++++--- 3 files changed, 18 insertions(+), 14 deletions(-) diff --git a/package.json b/package.json index ba7d6a4490..ce8c64f1c0 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "dependencies": { "derby": "git://github.com/codeparty/derby#master", "racer": "git://github.com/lefnire/racer#master", - "racer-db-mongo": "git://github.com/codeparty/racer-db-mongo#master", + "racer-db-mongo": "git://github.com/lefnire/racer-db-mongo#mongo-update", "derby-ui-boot": "git://github.com/codeparty/derby-ui-boot#master", "derby-auth": "git://github.com/lefnire/derby-auth#master", "connect-mongo": "0.2.0", diff --git a/src/app/schema.coffee b/src/app/schema.coffee index 480a337d26..95299a04fb 100644 --- a/src/app/schema.coffee +++ b/src/app/schema.coffee @@ -1,6 +1,7 @@ content = require './content' moment = require 'moment' _ = require 'underscore' +lodash = require 'lodash' derby = require 'derby' module.exports.newUserObject = -> @@ -65,22 +66,17 @@ module.exports.BatchUpdate = BatchUpdate = (model) -> userObj = undefined updates = {} { - queue: (path, val) -> - commit = model._commit - model._commit = (txn) -> - txn.isPrivate = true - commit.apply(this, arguments) - user.set(path, val) - model._commit = commit - updates[path] = val + queue: (path, val) -> updates[path] = val - getUser: -> userObj ?= user.get() + getUser: -> + userObj ?= lodash.cloneDeep(user.get()) # whaaa??? modifying userObj modifies the value of user.get() at that path? ### Handles updating the user model. If this is an en-mass operation (eg, server cron), pass the user object as {update}. otherwise, null means commit the changes immediately ### updateAndQueue: (path, val) -> + @queue path, val # Special function for setting object properties by string dot-notation. See http://stackoverflow.com/a/6394168/362790 arr = path.split('.') arr.reduce (curr, next, index) -> @@ -88,8 +84,15 @@ module.exports.BatchUpdate = BatchUpdate = (model) -> curr[next] = val curr[next] , @getUser() - @queue path, val commit: -> + commit = model._commit + model._commit = (txn) -> + txn.isPrivate = true + commit.apply(model, arguments) + _.each updates, (val, path) -> + if path == 'stats.hp' then debugger + user.set(path, val) + model._commit = commit user.set "update__", updates # some hackery in our own branched racer-db-mongo, see findAndModify } diff --git a/src/app/scoring.coffee b/src/app/scoring.coffee index d9a7611e9b..c294639b30 100644 --- a/src/app/scoring.coffee +++ b/src/app/scoring.coffee @@ -99,7 +99,6 @@ score = (taskId, direction, times, batch) -> times ?= 1 commit = !batch? - console.log {commit:commit} batch ?= new schema.BatchUpdate(model) userObj = batch.getUser() @@ -135,9 +134,11 @@ score = (taskId, direction, times, batch) -> adjustvalue = if (taskObj.up==false or taskObj.down==false) then false else true calculateDelta(adjustvalue) # Add habit value to habit-history (if different) - historyEntry = { date: +new Date(), value: value } if taskObj.value != value + historyEntry = { date: +new Date, value: value } if (delta > 0) then addPoints() else subtractPoints() - model.push "_user.#{taskPath}.history", historyEntry + taskObj.history ?= [] + taskObj.history.push historyEntry + batch.updateAndQueue "#{taskPath}.history", taskObj.history if taskObj.value != value when 'daily' calculateDelta() From 8471cafc468ba9babdf5c5b117e0c6a3af0fefc2 Mon Sep 17 00:00:00 2001 From: Tyler Renelle Date: Fri, 1 Feb 2013 12:07:21 -0500 Subject: [PATCH 26/51] txn.dontPersist for Store._sendToDb (see lefnire/racer#habitrpg) --- src/app/schema.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/schema.coffee b/src/app/schema.coffee index 95299a04fb..f63088a719 100644 --- a/src/app/schema.coffee +++ b/src/app/schema.coffee @@ -88,7 +88,7 @@ module.exports.BatchUpdate = BatchUpdate = (model) -> commit: -> commit = model._commit model._commit = (txn) -> - txn.isPrivate = true + txn.dontPersist = true commit.apply(model, arguments) _.each updates, (val, path) -> if path == 'stats.hp' then debugger From 97ce7588fd71ee061d955cfd7bc6ae8fbf789536 Mon Sep 17 00:00:00 2001 From: Tyler Renelle Date: Fri, 1 Feb 2013 12:14:45 -0500 Subject: [PATCH 27/51] use lefnire/ racer & racer-db-mongo #habitrpg branches --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index ce8c64f1c0..e4eb8e9832 100644 --- a/package.json +++ b/package.json @@ -5,8 +5,8 @@ "main": "./server.js", "dependencies": { "derby": "git://github.com/codeparty/derby#master", - "racer": "git://github.com/lefnire/racer#master", - "racer-db-mongo": "git://github.com/lefnire/racer-db-mongo#mongo-update", + "racer": "git://github.com/lefnire/racer#habitrpg", + "racer-db-mongo": "git://github.com/lefnire/racer-db-mongo#habitrpg", "derby-ui-boot": "git://github.com/codeparty/derby-ui-boot#master", "derby-auth": "git://github.com/lefnire/derby-auth#master", "connect-mongo": "0.2.0", From 8c46f6abe8f17b28dd1109cc77378b692507c658 Mon Sep 17 00:00:00 2001 From: Tyler Renelle Date: Fri, 1 Feb 2013 12:27:39 -0500 Subject: [PATCH 28/51] add cron back in on server --- src/server/index.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/server/index.coffee b/src/server/index.coffee index 1ac2071144..b9bf2bcc11 100644 --- a/src/server/index.coffee +++ b/src/server/index.coffee @@ -10,7 +10,7 @@ auth = require 'derby-auth' priv = require './private' ## Run server cron ## -#require('./cron').deleteStaleAccounts() +require('./cron').deleteStaleAccounts() ## RACER CONFIGURATION ## From 703deac359d6fa6b759ccb111108cfc72f076348 Mon Sep 17 00:00:00 2001 From: Tyler Renelle Date: Fri, 1 Feb 2013 13:22:00 -0500 Subject: [PATCH 29/51] cbug fixes. also have to explicitely get all user properties one-by-one, instead of user.get() for some reason --- src/app/index.coffee | 6 +++--- src/app/schema.coffee | 44 ++++++++++++++++++++++++------------------ src/app/scoring.coffee | 14 ++++++++------ 3 files changed, 36 insertions(+), 28 deletions(-) diff --git a/src/app/index.coffee b/src/app/index.coffee index 158b1fe342..92c748c1ab 100644 --- a/src/app/index.coffee +++ b/src/app/index.coffee @@ -46,7 +46,7 @@ get '/', (page, model, next) -> #user = result.at(0) model.ref '_user', user batch = new schema.BatchUpdate(model) - userObj = batch.getUser() + userObj = batch.userObj return page.redirect '/500.html' unless userObj? #this should never happen, but it is. Looking into it @@ -82,13 +82,13 @@ resetDom = (model) -> ready (model) -> user = model.at('_user') + scoring.setModel(model) #set cron immediately lastCron = user.get('lastCron') - user.set('lastCron', +new Date) if (!lastCron or lastCron == 'new') + user.set('lastCron', +new Date) if (!lastCron? or lastCron == 'new') # Setup model in scoring functions - scoring.setModel(model) scoring.cron(resetDom) # Load all the jQuery, Growl, Tour, etc diff --git a/src/app/schema.coffee b/src/app/schema.coffee index f63088a719..498dc1c82d 100644 --- a/src/app/schema.coffee +++ b/src/app/schema.coffee @@ -4,22 +4,24 @@ _ = require 'underscore' lodash = require 'lodash' derby = require 'derby' +userSchema = + lastCron: 'new' #this will be replaced with `+new Date` on first run + balance: 2 + stats: { money: 0, exp: 0, lvl: 1, hp: 50 } + items: { itemsEnabled: false, armor: 0, weapon: 0 } + notifications: { kickstarter: 'show' } + preferences: { gender: 'm', armorSet: 'v1' } + flags: { partyEnabled: false } + friends: [] + tasks: {} + habitIds: [] + dailyIds: [] + todoIds: [] + rewardIds: [] + module.exports.newUserObject = -> # deep clone, else further new users get duplicate objects - newUser = require('lodash').cloneDeep - lastCron: 'new' #this will be replaced with `+new Date` on first run - balance: 2 - stats: { money: 0, exp: 0, lvl: 1, hp: 50 } - items: { itemsEnabled: false, armor: 0, weapon: 0 } - notifications: { kickstarter: 'show' } - preferences: { gender: 'm', armorSet: 'v1' } - flags: { partyEnabled: false } - friends: [] - tasks: {} - habitIds: [] - dailyIds: [] - todoIds: [] - rewardIds: [] + newUser = require('lodash').cloneDeep userSchema for task in content.defaultTasks guid = task.id = require('racer').uuid() newUser.tasks[guid] = task @@ -31,7 +33,7 @@ module.exports.newUserObject = -> return newUser module.exports.updateUser = (batch) -> - userObj = batch.getUser() + userObj = batch.userObj batch.queue('notifications.kickstarter', 'show') unless userObj.notifications?.kickstarter? batch.queue('friends', []) unless !_.isEmpty(userObj.friends) @@ -63,13 +65,17 @@ module.exports.updateUser = (batch) -> module.exports.BatchUpdate = BatchUpdate = (model) -> user = model.at('_user') - userObj = undefined + + # this is really stupid, but i can't find how to get around user.get() making only available what has been gotten specifically before + obj = {} + _.each Object.keys(userSchema), (key) -> obj[key] = user.get(key) + userObj = lodash.cloneDeep obj # whaaa??? modifying userObj modifies the value of user.get() at that path? + updates = {} { queue: (path, val) -> updates[path] = val - getUser: -> - userObj ?= lodash.cloneDeep(user.get()) # whaaa??? modifying userObj modifies the value of user.get() at that path? + userObj: userObj ### Handles updating the user model. If this is an en-mass operation (eg, server cron), pass the user object as {update}. @@ -83,7 +89,7 @@ module.exports.BatchUpdate = BatchUpdate = (model) -> if (arr.length - 1) == index curr[next] = val curr[next] - , @getUser() + , userObj commit: -> commit = model._commit diff --git a/src/app/scoring.coffee b/src/app/scoring.coffee index c294639b30..501a2f8b21 100644 --- a/src/app/scoring.coffee +++ b/src/app/scoring.coffee @@ -59,7 +59,7 @@ taskDeltaFormula = (currentValue, direction) -> {update} if aggregated changes, pass in userObj as update. otherwise commits will be made immediately ### updateStats = (newStats, batch) -> - userObj = batch.getUser() + userObj = batch.userObj # if user is dead, dont do anything return if userObj.stats.lvl == 0 @@ -98,9 +98,11 @@ updateStats = (newStats, batch) -> score = (taskId, direction, times, batch) -> times ?= 1 - commit = !batch? - batch ?= new schema.BatchUpdate(model) - userObj = batch.getUser() + commit = false + unless batch? + commit = true + batch = new schema.BatchUpdate(model) + userObj = batch.userObj {money, hp, exp, lvl} = userObj.stats @@ -178,7 +180,7 @@ cron = (resetDom_cb) -> if daysPassed > 0 user.set 'lastCron', today batch = new schema.BatchUpdate(model) - userObj = batch.getUser() + userObj = batch.userObj hpBefore = userObj.stats.hp #we'll use this later so we can animate hp loss # Tally each task todoTally = 0 @@ -200,7 +202,7 @@ cron = (resetDom_cb) -> thatDay = moment().subtract('days', n+1) if repeat[helpers.dayMapping[thatDay.day()]]==true daysFailed++ - score id, 'down', daysFailed, userObj + score id, 'down', daysFailed, batch value = taskObj.value #get updated value if type == 'daily' From 6e93200fb9f2790d5d18d6a5423dbc83a0422ded Mon Sep 17 00:00:00 2001 From: Tyler Renelle Date: Fri, 1 Feb 2013 13:29:29 -0500 Subject: [PATCH 30/51] always set preened lists --- src/app/schema.coffee | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/app/schema.coffee b/src/app/schema.coffee index 498dc1c82d..5d2c53f376 100644 --- a/src/app/schema.coffee +++ b/src/app/schema.coffee @@ -60,16 +60,15 @@ module.exports.updateUser = (batch) -> preened = _.filter(union, (val) -> _.contains(taskIds, val)) # There were indeed issues found, set the new list - # TODO _.difference might still be empty for duplicates in one list? - batch.queue(path, preened) if _.difference(preened, userObj[path]).length != 0 + batch.queue(path, preened) # if _.difference(preened, userObj[path]).length != 0 module.exports.BatchUpdate = BatchUpdate = (model) -> user = model.at('_user') # this is really stupid, but i can't find how to get around user.get() making only available what has been gotten specifically before - obj = {} - _.each Object.keys(userSchema), (key) -> obj[key] = user.get(key) - userObj = lodash.cloneDeep obj # whaaa??? modifying userObj modifies the value of user.get() at that path? + userObj = {} + _.each Object.keys(userSchema), (key) -> userObj[key] = lodash.cloneDeep user.get(key) +# userObj = lodash.cloneDeep obj # whaaa??? modifying userObj modifies the value of user.get() at that path? updates = {} { @@ -97,7 +96,6 @@ module.exports.BatchUpdate = BatchUpdate = (model) -> txn.dontPersist = true commit.apply(model, arguments) _.each updates, (val, path) -> - if path == 'stats.hp' then debugger user.set(path, val) model._commit = commit user.set "update__", updates # some hackery in our own branched racer-db-mongo, see findAndModify From 53d5ae51c536f697f4ab318786cbea942c021735 Mon Sep 17 00:00:00 2001 From: Tyler Renelle Date: Fri, 1 Feb 2013 13:49:18 -0500 Subject: [PATCH 31/51] cron bug --- src/app/scoring.coffee | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/app/scoring.coffee b/src/app/scoring.coffee index 501a2f8b21..07e9aee966 100644 --- a/src/app/scoring.coffee +++ b/src/app/scoring.coffee @@ -95,11 +95,11 @@ updateStats = (newStats, batch) -> # {direction} 'up' or 'down' # {times} # times to call score on this task (1 unless cron, usually) # {update} if we're running updates en-mass (eg, cron on server) pass in userObj -score = (taskId, direction, times, batch) -> +score = (taskId, direction, times, batch, cron) -> times ?= 1 commit = false - unless batch? + unless batch commit = true batch = new schema.BatchUpdate(model) userObj = batch.userObj @@ -144,14 +144,14 @@ score = (taskId, direction, times, batch) -> when 'daily' calculateDelta() - if update? # cron + if cron? # cron subtractPoints() else addPoints() # obviously for delta>0, but also a trick to undo accidental checkboxes when 'todo' calculateDelta() - unless update? # don't touch stats on cron + unless cron? # don't touch stats on cron addPoints() # obviously for delta>0, but also a trick to undo accidental checkboxes when 'reward' @@ -202,7 +202,7 @@ cron = (resetDom_cb) -> thatDay = moment().subtract('days', n+1) if repeat[helpers.dayMapping[thatDay.day()]]==true daysFailed++ - score id, 'down', daysFailed, batch + score id, 'down', daysFailed, batch, true value = taskObj.value #get updated value if type == 'daily' From 86ea99c2dc6aaa9fc6302e684c9ece7193e42aca Mon Sep 17 00:00:00 2001 From: Tyler Renelle Date: Fri, 1 Feb 2013 14:05:52 -0500 Subject: [PATCH 32/51] add "emulate next day" debugging button --- src/app/index.coffee | 5 +++++ views/app/index.html | 3 +++ 2 files changed, 8 insertions(+) diff --git a/src/app/index.coffee b/src/app/index.coffee index 92c748c1ab..20798fc15e 100644 --- a/src/app/index.coffee +++ b/src/app/index.coffee @@ -307,3 +307,8 @@ ready (model) -> else model.set "_view.addFriendError", "User with id #{friendId} not found." + exports.emulateNextDay = -> + yesterday = moment().subtract('days', 1).toString() + user.set 'lastCron', yesterday + window.location.reload() + diff --git a/views/app/index.html b/views/app/index.html index 8ef73b5b3d..820f45870c 100644 --- a/views/app/index.html +++ b/views/app/index.html @@ -308,6 +308,9 @@