mirror of
https://github.com/codeninjasllc/codecombat.git
synced 2025-04-26 14:03:28 -04:00
A few poll fixes.
This commit is contained in:
parent
8c1de9dfa2
commit
9c99fc455a
6 changed files with 132 additions and 116 deletions
app
models
styles/play/modal
templates/play/modal
views/play/modal
server
|
@ -118,6 +118,7 @@ module.exports = class User extends CocoModel
|
|||
@announcesActionAudioGroup
|
||||
|
||||
# Signs and Portents was receiving updates after test started, and also had a big bug on March 4, so just look at test from March 5 on.
|
||||
# ... and stopped working well until another update on March 10, so maybe March 11+...
|
||||
getFourthLevelGroup: ->
|
||||
return @fourthLevelGroup if @fourthLevelGroup
|
||||
group = me.get('testGroupNumber') % 8
|
||||
|
|
|
@ -118,14 +118,16 @@
|
|||
|
||||
.progress-bar
|
||||
background-color: rgb(245, 170, 49)
|
||||
border-radius: 10px
|
||||
border: 3px solid rgb(45, 36, 29)
|
||||
@include transition(none)
|
||||
|
||||
&.votes-cell
|
||||
max-width: 34px
|
||||
|
||||
.vote-percentage.badge
|
||||
.badge
|
||||
background-color: rgb(245, 170, 49)
|
||||
text-shadow: -1px -1px 0px black, 1px 1px 0px black, -1px 1px 0px black, 1px -1px 0px black
|
||||
color: rgb(45, 36, 29)
|
||||
|
||||
table:not(.answered)
|
||||
tr
|
||||
|
|
|
@ -23,6 +23,9 @@ block modal-body-content
|
|||
.progress-bar
|
||||
td.votes-cell
|
||||
span.badge.vote-percentage
|
||||
if me.isAdmin()
|
||||
td.votes-cell
|
||||
span.badge.vote-count
|
||||
|
||||
.random-gems-container-wrapper
|
||||
.random-gems-container
|
||||
|
|
|
@ -66,6 +66,7 @@ module.exports = class PollModal extends ModalView
|
|||
votePercentage = Math.round(100 * votes / totalVotes) + '%'
|
||||
$answer.find('.progress-bar').css('width', '0%').animate({width: widthPercentage}, 'slow')
|
||||
$answer.find('.vote-percentage').text votePercentage
|
||||
$answer.find('.vote-count').text votes if me.isAdmin()
|
||||
|
||||
@trigger 'vote-updated'
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ Handler = require '../commons/Handler'
|
|||
LocalMongo = require '../../app/lib/LocalMongo'
|
||||
util = require '../../app/core/utils'
|
||||
LevelSession = require '../levels/sessions/LevelSession'
|
||||
UserPollsRecord = require '../polls/UserPollsRecord'
|
||||
|
||||
class EarnedAchievementHandler extends Handler
|
||||
modelClass: EarnedAchievement
|
||||
|
@ -191,126 +192,134 @@ class EarnedAchievementHandler extends Handler
|
|||
# Keep track of a user's already achieved in order to set the notified values correctly
|
||||
userID = user.get('_id').toHexString()
|
||||
|
||||
# Fetch all of a user's earned achievements
|
||||
EarnedAchievement.find {user: userID}, (err, alreadyEarned) ->
|
||||
alreadyEarnedIDs = []
|
||||
previousPoints = 0
|
||||
previousRewards = heroes: [], items: [], levels: [], gems: 0
|
||||
async.each alreadyEarned, ((earned, doneWithEarned) ->
|
||||
if (_.find achievements, (single) -> earned.get('achievement') is single.get('_id').toHexString()) # if already earned
|
||||
alreadyEarnedIDs.push earned.get('achievement') + ''
|
||||
previousPoints += earned.get 'earnedPoints'
|
||||
for rewardType in ['heroes', 'items', 'levels']
|
||||
previousRewards[rewardType] = previousRewards[rewardType].concat(earned.get('earnedRewards')?[rewardType] ? [])
|
||||
previousRewards.gems += earned.get('earnedRewards')?.gems ? 0
|
||||
doneWithEarned()
|
||||
), (err) -> # After checking already achieved
|
||||
# Fetch a user's poll record so we can get the gems they should have from that.
|
||||
UserPollsRecord.findOne {user: userID}, (err, userPollsRecord) ->
|
||||
log.error err if err
|
||||
pollGems = 0
|
||||
for pollID, reward of userPollsRecord?.get('rewards') or {}
|
||||
pollGems += Math.ceil 2 * reward.random * reward.level
|
||||
|
||||
# Fetch all of a user's earned achievements
|
||||
EarnedAchievement.find {user: userID}, (err, alreadyEarned) ->
|
||||
log.error err if err
|
||||
# TODO maybe also delete earned? Make sure you don't delete too many
|
||||
|
||||
newTotalPoints = 0
|
||||
newTotalRewards = heroes: [], items: [], levels: [], gems: 0
|
||||
|
||||
async.each achievements, ((achievement, doneWithAchievement) ->
|
||||
isRepeatable = achievement.get('proportionalTo')?
|
||||
model = mongoose.modelNameByCollection(achievement.get('collection'))
|
||||
return doneWithAchievement new Error "Model with collection '#{achievement.get 'collection'}' doesn't exist." unless model?
|
||||
|
||||
finalQuery = _.clone achievement.get 'query'
|
||||
return doneWithAchievement() if _.isEmpty finalQuery
|
||||
finalQuery.$or = [{}, {}] # Allow both ObjectIDs or hex string IDs
|
||||
finalQuery.$or[0][achievement.userField] = userID
|
||||
finalQuery.$or[1][achievement.userField] = mongoose.Types.ObjectId userID
|
||||
|
||||
model.findOne finalQuery, (err, something) ->
|
||||
return doneWithAchievement() if _.isEmpty something
|
||||
|
||||
#log.debug "Matched an achievement: #{achievement.get 'name'} for #{user.get 'name'}"
|
||||
|
||||
earned =
|
||||
user: userID
|
||||
achievement: achievement._id.toHexString()
|
||||
achievementName: achievement.get 'name'
|
||||
notified: achievement._id.toHexString() in alreadyEarnedIDs
|
||||
|
||||
if isRepeatable
|
||||
earned.achievedAmount = util.getByPath(something.toObject(), achievement.get 'proportionalTo') or 0
|
||||
earned.previouslyAchievedAmount = 0
|
||||
|
||||
expFunction = achievement.getExpFunction()
|
||||
newPoints = expFunction(earned.achievedAmount) * achievement.get('worth') ? 10
|
||||
newGems = expFunction(earned.achievedAmount) * (achievement.get('rewards')?.gems ? 0)
|
||||
else
|
||||
newPoints = achievement.get('worth') ? 10
|
||||
newGems = achievement.get('rewards')?.gems ? 0
|
||||
|
||||
earned.earnedPoints = newPoints
|
||||
newTotalPoints += newPoints
|
||||
|
||||
earned.earnedRewards = achievement.get('rewards')
|
||||
alreadyEarnedIDs = []
|
||||
previousPoints = 0
|
||||
previousRewards = heroes: [], items: [], levels: [], gems: 0
|
||||
async.each alreadyEarned, ((earned, doneWithEarned) ->
|
||||
if (_.find achievements, (single) -> earned.get('achievement') is single.get('_id').toHexString()) # if already earned
|
||||
alreadyEarnedIDs.push earned.get('achievement') + ''
|
||||
previousPoints += earned.get 'earnedPoints'
|
||||
for rewardType in ['heroes', 'items', 'levels']
|
||||
newTotalRewards[rewardType] = newTotalRewards[rewardType].concat(achievement.get('rewards')?[rewardType] ? [])
|
||||
if isRepeatable and earned.earnedRewards
|
||||
earned.earnedRewards = _.clone earned.earnedRewards
|
||||
earned.earnedRewards.gems = newGems
|
||||
newTotalRewards.gems += newGems
|
||||
|
||||
EarnedAchievement.update {achievement:earned.achievement, user:earned.user}, earned, {upsert: true}, (err) ->
|
||||
doneWithAchievement err
|
||||
), (err) -> # Wrap up a user, save points
|
||||
previousRewards[rewardType] = previousRewards[rewardType].concat(earned.get('earnedRewards')?[rewardType] ? [])
|
||||
previousRewards.gems += earned.get('earnedRewards')?.gems ? 0
|
||||
doneWithEarned()
|
||||
), (err) -> # After checking already achieved
|
||||
log.error err if err
|
||||
#console.log 'User', user.get('name'), 'had newTotalPoints', newTotalPoints, 'and newTotalRewards', newTotalRewards, 'previousRewards', previousRewards
|
||||
return doneWithUser(user) unless newTotalPoints or newTotalRewards.gems or _.some(newTotalRewards, (r) -> r.length)
|
||||
#log.debug "Matched a total of #{newTotalPoints} new points"
|
||||
#log.debug "Incrementing score for these achievements with #{newTotalPoints - previousPoints}"
|
||||
pointDelta = newTotalPoints - previousPoints
|
||||
pctDone = (100 * usersFinished / total).toFixed(2)
|
||||
console.log "Updated points to #{newTotalPoints} (#{if pointDelta < 0 then '' else '+'}#{pointDelta}) for #{user.get('name') or '???'} (#{user.get('_id')}) (#{pctDone}%)"
|
||||
if recalculatingAll
|
||||
update = {$set: {points: newTotalPoints, 'earned.gems': 0, 'earned.heroes': [], 'earned.items': [], 'earned.levels': []}}
|
||||
else
|
||||
update = {$inc: {points: pointDelta}}
|
||||
secondUpdate = {} # In case we need to pull, then push.
|
||||
for rewardType, rewards of newTotalRewards
|
||||
updateKey = "earned.#{rewardType}"
|
||||
if rewardType is 'gems'
|
||||
if recalculatingAll
|
||||
update.$set[updateKey] = rewards
|
||||
# TODO maybe also delete earned? Make sure you don't delete too many
|
||||
|
||||
newTotalPoints = 0
|
||||
newTotalRewards = heroes: [], items: [], levels: [], gems: 0
|
||||
|
||||
async.each achievements, ((achievement, doneWithAchievement) ->
|
||||
isRepeatable = achievement.get('proportionalTo')?
|
||||
model = mongoose.modelNameByCollection(achievement.get('collection'))
|
||||
return doneWithAchievement new Error "Model with collection '#{achievement.get 'collection'}' doesn't exist." unless model?
|
||||
|
||||
finalQuery = _.clone achievement.get 'query'
|
||||
return doneWithAchievement() if _.isEmpty finalQuery
|
||||
finalQuery.$or = [{}, {}] # Allow both ObjectIDs or hex string IDs
|
||||
finalQuery.$or[0][achievement.userField] = userID
|
||||
finalQuery.$or[1][achievement.userField] = mongoose.Types.ObjectId userID
|
||||
|
||||
model.findOne finalQuery, (err, something) ->
|
||||
return doneWithAchievement() if _.isEmpty something
|
||||
|
||||
#log.debug "Matched an achievement: #{achievement.get 'name'} for #{user.get 'name'}"
|
||||
|
||||
earned =
|
||||
user: userID
|
||||
achievement: achievement._id.toHexString()
|
||||
achievementName: achievement.get 'name'
|
||||
notified: achievement._id.toHexString() in alreadyEarnedIDs
|
||||
|
||||
if isRepeatable
|
||||
earned.achievedAmount = util.getByPath(something.toObject(), achievement.get 'proportionalTo') or 0
|
||||
earned.previouslyAchievedAmount = 0
|
||||
|
||||
expFunction = achievement.getExpFunction()
|
||||
newPoints = expFunction(earned.achievedAmount) * achievement.get('worth') ? 10
|
||||
newGems = expFunction(earned.achievedAmount) * (achievement.get('rewards')?.gems ? 0)
|
||||
else
|
||||
update.$inc[updateKey] = rewards - previousRewards.gems
|
||||
newPoints = achievement.get('worth') ? 10
|
||||
newGems = achievement.get('rewards')?.gems ? 0
|
||||
|
||||
earned.earnedPoints = newPoints
|
||||
newTotalPoints += newPoints
|
||||
|
||||
earned.earnedRewards = achievement.get('rewards')
|
||||
for rewardType in ['heroes', 'items', 'levels']
|
||||
newTotalRewards[rewardType] = newTotalRewards[rewardType].concat(achievement.get('rewards')?[rewardType] ? [])
|
||||
if isRepeatable and earned.earnedRewards
|
||||
earned.earnedRewards = _.clone earned.earnedRewards
|
||||
earned.earnedRewards.gems = newGems
|
||||
newTotalRewards.gems += newGems
|
||||
|
||||
EarnedAchievement.update {achievement:earned.achievement, user:earned.user}, earned, {upsert: true}, (err) ->
|
||||
doneWithAchievement err
|
||||
), (err) -> # Wrap up a user, save points
|
||||
log.error err if err
|
||||
#console.log 'User', user.get('name'), 'had newTotalPoints', newTotalPoints, 'and newTotalRewards', newTotalRewards, 'previousRewards', previousRewards
|
||||
return doneWithUser(user) unless newTotalPoints or newTotalRewards.gems or _.some(newTotalRewards, (r) -> r.length)
|
||||
#log.debug "Matched a total of #{newTotalPoints} new points"
|
||||
#log.debug "Incrementing score for these achievements with #{newTotalPoints - previousPoints}"
|
||||
pointDelta = newTotalPoints - previousPoints
|
||||
pctDone = (100 * usersFinished / total).toFixed(2)
|
||||
console.log "Updated points to #{newTotalPoints} (#{if pointDelta < 0 then '' else '+'}#{pointDelta}) for #{user.get('name') or '???'} (#{user.get('_id')}) (#{pctDone}%)"
|
||||
if recalculatingAll
|
||||
update = {$set: {points: newTotalPoints, 'earned.gems': 0, 'earned.heroes': [], 'earned.items': [], 'earned.levels': []}}
|
||||
else
|
||||
if recalculatingAll
|
||||
update.$set[updateKey] = _.uniq rewards
|
||||
update = {$inc: {points: pointDelta}}
|
||||
secondUpdate = {} # In case we need to pull, then push.
|
||||
for rewardType, rewards of newTotalRewards
|
||||
updateKey = "earned.#{rewardType}"
|
||||
if rewardType is 'gems'
|
||||
if recalculatingAll
|
||||
update.$set[updateKey] = rewards + pollGems
|
||||
else
|
||||
update.$inc[updateKey] = rewards - previousRewards.gems
|
||||
else
|
||||
if recalculatingAll
|
||||
update.$set[updateKey] = _.uniq rewards
|
||||
else
|
||||
previousCounts = _.countBy previousRewards[rewardType]
|
||||
newCounts = _.countBy rewards
|
||||
relevantRewards = _.union _.keys(previousCounts), _.keys(newCounts)
|
||||
for reward in relevantRewards
|
||||
[previousCount, newCount] = [previousCounts[reward], newCounts[reward]]
|
||||
if newCount and not previousCount
|
||||
update.$addToSet ?= {}
|
||||
update.$addToSet[updateKey] ?= {$each: []}
|
||||
update.$addToSet[updateKey].$each.push reward
|
||||
else if previousCount and not newCount
|
||||
# Might $pull $each also work here?
|
||||
update.$pullAll ?= {}
|
||||
update.$pullAll[updateKey] ?= []
|
||||
update.$pullAll[updateKey].push reward
|
||||
if update.$addToSet?[updateKey] and update.$pullAll?[updateKey]
|
||||
# Perform the update in two calls to avoid "MongoError: Cannot update 'earned.levels' and 'earned.levels' at the same time"
|
||||
secondUpdate.$addToSet ?= {}
|
||||
secondUpdate.$addToSet[updateKey] = update.$addToSet[updateKey]
|
||||
delete update.$addToSet[updateKey]
|
||||
delete update.$addToSet unless _.size update.$addToSet
|
||||
#console.log 'recalculatingAll?', recalculatingAll, 'so update is', update, 'secondUpdate', secondUpdate
|
||||
User.update {_id: userID}, update, {}, (err) ->
|
||||
log.error err if err?
|
||||
if _.size secondUpdate
|
||||
User.update {_id: userID}, secondUpdate, {}, (err) ->
|
||||
log.error err if err?
|
||||
doneWithUser user
|
||||
else
|
||||
previousCounts = _.countBy previousRewards[rewardType]
|
||||
newCounts = _.countBy rewards
|
||||
relevantRewards = _.union _.keys(previousCounts), _.keys(newCounts)
|
||||
for reward in relevantRewards
|
||||
[previousCount, newCount] = [previousCounts[reward], newCounts[reward]]
|
||||
if newCount and not previousCount
|
||||
update.$addToSet ?= {}
|
||||
update.$addToSet[updateKey] ?= {$each: []}
|
||||
update.$addToSet[updateKey].$each.push reward
|
||||
else if previousCount and not newCount
|
||||
# Might $pull $each also work here?
|
||||
update.$pullAll ?= {}
|
||||
update.$pullAll[updateKey] ?= []
|
||||
update.$pullAll[updateKey].push reward
|
||||
if update.$addToSet?[updateKey] and update.$pullAll?[updateKey]
|
||||
# Perform the update in two calls to avoid "MongoError: Cannot update 'earned.levels' and 'earned.levels' at the same time"
|
||||
secondUpdate.$addToSet ?= {}
|
||||
secondUpdate.$addToSet[updateKey] = update.$addToSet[updateKey]
|
||||
delete update.$addToSet[updateKey]
|
||||
delete update.$addToSet unless _.size update.$addToSet
|
||||
#console.log 'recalculatingAll?', recalculatingAll, 'so update is', update, 'secondUpdate', secondUpdate
|
||||
User.update {_id: userID}, update, {}, (err) ->
|
||||
log.error err if err?
|
||||
if _.size secondUpdate
|
||||
User.update {_id: userID}, secondUpdate, {}, (err) ->
|
||||
log.error err if err?
|
||||
doneWithUser user
|
||||
else
|
||||
doneWithUser user
|
||||
|
||||
|
||||
module.exports = new EarnedAchievementHandler()
|
||||
|
|
|
@ -32,7 +32,7 @@ PollHandler = class PollHandler extends Handler
|
|||
@sendSuccess res, @formatEntity(req, poll)
|
||||
|
||||
findPollPriority: (lastPollID, callback) ->
|
||||
return callback null, -9001 #unless lastPollID
|
||||
return callback null, -9001 unless lastPollID
|
||||
Poll.findById mongoose.Types.ObjectId(lastPollID), 'priority', {lean: true}, (err, poll) ->
|
||||
callback err, poll?.priority
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue