Have client check for achievement updates

This commit is contained in:
Scott Erickson 2016-08-26 16:25:19 -07:00
parent 139efe4cf7
commit cf9d082ffa
6 changed files with 86 additions and 43 deletions

View file

@ -44,42 +44,53 @@ window.console ?=
debug: ->
console.debug ?= console.log # Needed for IE10 and earlier
Application = initialize: ->
Router = require('core/Router')
@isProduction = -> document.location.href.search('https?://localhost') is -1
@isIPadApp = webkit?.messageHandlers? and navigator.userAgent?.indexOf('CodeCombat-iPad') isnt -1
$('body').addClass 'ipad' if @isIPadApp
$('body').addClass 'picoctf' if window.serverConfig.picoCTF
if $.browser.msie and parseInt($.browser.version) is 10
$("html").addClass("ie10")
@tracker = new Tracker()
@facebookHandler = new FacebookHandler()
@gplusHandler = new GPlusHandler()
@githubHandler = new GitHubHandler()
@moduleLoader = new ModuleLoader()
@moduleLoader.loadLanguage(me.get('preferredLanguage', true))
$(document).bind 'keydown', preventBackspace
preload(COMMON_FILES)
CocoModel.pollAchievements()
$.i18n.init {
lng: me.get('preferredLanguage', true)
fallbackLng: 'en'
resStore: locale
useDataAttrOptions: true
#debug: true
#sendMissing: true
#sendMissingTo: 'current'
#resPostPath: '/languages/add/__lng__/__ns__'
}, (t) =>
@router = new Router()
onIdleChanged = (to) => => Backbone.Mediator.publish 'application:idle-changed', idle: @userIsIdle = to
@idleTracker = new Idle
onAway: onIdleChanged true
onAwayBack: onIdleChanged false
onHidden: onIdleChanged true
onVisible: onIdleChanged false
awayTimeout: 5 * 60 * 1000
@idleTracker.start()
Application = {
initialize: ->
Router = require('core/Router')
@isProduction = -> document.location.href.search('https?://localhost') is -1
@isIPadApp = webkit?.messageHandlers? and navigator.userAgent?.indexOf('CodeCombat-iPad') isnt -1
$('body').addClass 'ipad' if @isIPadApp
$('body').addClass 'picoctf' if window.serverConfig.picoCTF
if $.browser.msie and parseInt($.browser.version) is 10
$("html").addClass("ie10")
@tracker = new Tracker()
@facebookHandler = new FacebookHandler()
@gplusHandler = new GPlusHandler()
@githubHandler = new GitHubHandler()
@moduleLoader = new ModuleLoader()
@moduleLoader.loadLanguage(me.get('preferredLanguage', true))
$(document).bind 'keydown', preventBackspace
preload(COMMON_FILES)
CocoModel.pollAchievements()
# @checkForNewAchievement() # TODO: Enable once thoroughly tested
$.i18n.init {
lng: me.get('preferredLanguage', true)
fallbackLng: 'en'
resStore: locale
useDataAttrOptions: true
#debug: true
#sendMissing: true
#sendMissingTo: 'current'
#resPostPath: '/languages/add/__lng__/__ns__'
}, (t) =>
@router = new Router()
onIdleChanged = (to) => => Backbone.Mediator.publish 'application:idle-changed', idle: @userIsIdle = to
@idleTracker = new Idle
onAway: onIdleChanged true
onAwayBack: onIdleChanged false
onHidden: onIdleChanged true
onVisible: onIdleChanged false
awayTimeout: 5 * 60 * 1000
@idleTracker.start()
checkForNewAchievement: ->
id = me.get('lastAchievementChecked') or me.id
lastAchievementChecked = new Date(parseInt(id.substring(0, 8), 16) * 1000)
daysSince = moment.duration(new Date() - lastAchievementChecked).asDays()
if daysSince > 1
me.checkForNewAchievement()
setTimeout(_.bind(@checkForNewAchievement, @), moment.duration(1, 'minute').asMilliseconds())
}
module.exports = Application
window.application = Application

View file

@ -368,6 +368,11 @@ module.exports = class User extends CocoModel
options.url = _.result(@, 'url') + '/deteacher'
options.type = 'POST'
@fetch(options)
checkForNewAchievement: (options={}) ->
options.url = _.result(@, 'url') + '/check-for-new-achievement'
options.type = 'POST'
@fetch(options)
tiersByLevel = [-1, 0, 0.05, 0.14, 0.18, 0.32, 0.41, 0.5, 0.64, 0.82, 0.91, 1.04, 1.22, 1.35, 1.48, 1.65, 1.78, 1.96, 2.1, 2.24, 2.38, 2.55, 2.69, 2.86, 3.03, 3.16, 3.29, 3.42, 3.58, 3.74, 3.89, 4.04, 4.19, 4.32, 4.47, 4.64, 4.79, 4.96,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 10, 10.5, 11, 11.5, 12, 12.5, 13, 13.5, 14, 14.5, 15

View file

@ -344,6 +344,7 @@ _.extend UserSchema.properties,
schoolName: {type: 'string'}
role: {type: 'string', enum: ["God", "advisor", "parent", "principal", "student", "superintendent", "teacher", "technology coordinator"]}
birthday: c.stringDate({title: "Birthday"})
lastAchievementChecked: c.objectId({ name: 'Last Achievement Checked' })
c.extendBasicProperties UserSchema, 'user'

View file

@ -267,7 +267,7 @@ module.exports =
if not achievement
userUpdate = { 'lastAchievementChecked': new mongoose.Types.ObjectId() }
user.update(userUpdate)
user.update({$set: userUpdate}).exec()
return res.send(userUpdate)
userUpdate = { 'lastAchievementChecked': achievement._id }
@ -283,19 +283,19 @@ module.exports =
})
else
userUpdate = { 'lastAchievementChecked': new mongoose.Types.ObjectId() }
user.update(userUpdate)
user.update({$set: userUpdate}).exec()
return res.send(userUpdate)
trigger = _.find(triggers, (trigger) -> LocalMongo.matchesQuery(trigger.toObject(), query))
if not trigger
user.update(userUpdate)
user.update({$set: userUpdate}).exec()
return res.send(userUpdate)
earned = yield EarnedAchievement.findOne({ achievement: achievement.id, user: req.user })
yield [
EarnedAchievement.upsertFor(achievement, trigger, earned, req.user)
user.update(userUpdate)
user.update({$set: userUpdate})
]
user = yield User.findById(user.id).select({points: 1, earned: 1})
return res.send(_.assign({}, userUpdate, user.toObject()))

View file

@ -34,8 +34,9 @@ EarnedAchievementSchema.statics.upsertFor = (achievement, trigger, earned, user)
# make sure user has all the levels and items they should have
update = {}
for rewardType, rewards of achievement.get('rewards') ? {}
continue if rewardType is 'gems'
if rewards.length
if rewardType is 'gems'
update.$inc = { 'earned.gems': rewards - (actuallyEarned.gems ? 0) }
else if rewards.length
update.$addToSet ?= {}
update.$addToSet["earned.#{rewardType}"] = { $each: rewards }
yield user.update(update)
@ -54,7 +55,7 @@ EarnedAchievementSchema.statics.createForAchievement = co.wrap (achievement, doc
User = require('./User')
userObjectID = doc.get(achievement.get('userField'))
userID = if _.isObject userObjectID then userObjectID.toHexString() else userObjectID # Standardize! Use ObjectIds
userID = if _.isObject userObjectID then userObjectID.toHexString() else userObjectID # TODO: Migrate to ObjectIds
earnedAttrs = {
user: userID

View file

@ -233,6 +233,31 @@ describe 'POST /db/earned_achievement', ->
user = yield User.findById(user.id)
expect(user.get('earned').levels[0]).toBe(lockedLevelID)
done()
it 'updates the user\'s gems if the achievement gems changed', utils.wrap (done) ->
user = yield utils.initUser()
yield utils.loginUser(user)
# get the User the unlockable achievement, check they got their reward
session = new LevelSession({
permissions: simplePermissions
creator: user._id
level: original: 'dungeon-arena'
})
yield session.save()
json = {achievement: @unlockable.id, triggeredBy: session._id, collection: 'level.sessions'}
[res, body] = yield request.postAsync { url: eaURL, json }
user = yield User.findById(user.id)
expect(user.get('earned').levels[0]).toBe(lockedLevelID)
# change the achievement
yield @unlockable.update({ $set: { 'rewards.gems': 100 } })
# hit the endpoint again, make sure gems were updated
[res, body] = yield request.postAsync { url: eaURL, json }
user = yield User.findById(user.id)
expect(user.get('earned').gems).toBe(100)
done()
describe 'automatically achieving achievements', ->
beforeEach addAllAchievements