2014-05-13 16:46:56 -04:00
|
|
|
mongoose = require('mongoose')
|
|
|
|
Achievement = require('../achievements/Achievement')
|
2014-05-18 07:21:27 -04:00
|
|
|
EarnedAchievement = require '../achievements/EarnedAchievement'
|
2014-05-22 10:59:01 -04:00
|
|
|
User = require '../users/User'
|
2014-05-18 07:21:27 -04:00
|
|
|
LocalMongo = require '../../app/lib/LocalMongo'
|
2014-05-18 13:58:30 -04:00
|
|
|
util = require '../../app/lib/utils'
|
2014-05-31 17:55:26 -04:00
|
|
|
log = require 'winston'
|
2014-05-13 16:46:56 -04:00
|
|
|
|
|
|
|
achievements = {}
|
|
|
|
|
|
|
|
loadAchievements = ->
|
|
|
|
achievements = {}
|
|
|
|
query = Achievement.find({})
|
|
|
|
query.exec (err, docs) ->
|
|
|
|
_.each docs, (achievement) ->
|
2014-05-19 19:25:41 -04:00
|
|
|
category = achievement.get 'collection'
|
2014-05-18 07:21:27 -04:00
|
|
|
achievements[category] = [] unless category of achievements
|
|
|
|
achievements[category].push achievement
|
2014-05-13 16:46:56 -04:00
|
|
|
loadAchievements()
|
|
|
|
|
|
|
|
module.exports = AchievablePlugin = (schema, options) ->
|
|
|
|
checkForAchievement = (doc) ->
|
|
|
|
collectionName = doc.constructor.modelName
|
|
|
|
|
2014-05-18 07:21:27 -04:00
|
|
|
before = {}
|
2014-05-13 16:46:56 -04:00
|
|
|
|
|
|
|
schema.post 'init', (doc) ->
|
2014-05-18 11:24:21 -04:00
|
|
|
before[doc.id] = doc.toObject()
|
|
|
|
|
2014-05-13 16:46:56 -04:00
|
|
|
schema.post 'save', (doc) ->
|
2014-05-18 07:21:27 -04:00
|
|
|
isNew = not doc.isInit('_id')
|
2014-05-18 13:58:30 -04:00
|
|
|
originalDocObj = before[doc.id] unless isNew
|
2014-05-18 07:21:27 -04:00
|
|
|
|
|
|
|
category = doc.constructor.modelName
|
|
|
|
|
|
|
|
if category of achievements
|
|
|
|
docObj = doc.toObject()
|
|
|
|
for achievement in achievements[category]
|
|
|
|
query = achievement.get('query')
|
|
|
|
isRepeatable = achievement.get('proportionalTo')?
|
2014-05-18 13:58:30 -04:00
|
|
|
alreadyAchieved = if isNew then false else LocalMongo.matchesQuery originalDocObj, query
|
|
|
|
newlyAchieved = LocalMongo.matchesQuery(docObj, query)
|
2014-05-31 17:55:26 -04:00
|
|
|
log.debug 'isRepeatable: ' + isRepeatable
|
|
|
|
log.debug 'alreadyAchieved: ' + alreadyAchieved
|
|
|
|
log.debug 'newlyAchieved: ' + newlyAchieved
|
2014-05-18 13:58:30 -04:00
|
|
|
|
|
|
|
userObjectID = doc.get(achievement.get('userField'))
|
|
|
|
userID = if _.isObject userObjectID then userObjectID.toHexString() else userObjectID # Standardize! Use strings, not ObjectId's
|
|
|
|
|
2014-05-19 19:25:41 -04:00
|
|
|
if newlyAchieved and (not alreadyAchieved or isRepeatable)
|
|
|
|
earned = {
|
2014-05-18 13:58:30 -04:00
|
|
|
user: userID
|
|
|
|
achievement: achievement._id.toHexString()
|
2014-05-18 07:21:27 -04:00
|
|
|
achievementName: achievement.get 'name'
|
2014-05-19 19:25:41 -04:00
|
|
|
}
|
2014-05-26 12:21:56 -04:00
|
|
|
earnedPoints = 0
|
|
|
|
wrapUp = ->
|
|
|
|
# Update user's experience points
|
|
|
|
User.update({_id: userID}, {$inc: {points: earnedPoints}}, {}, (err, count) ->
|
|
|
|
console.error err if err?
|
|
|
|
)
|
|
|
|
|
2014-05-31 17:19:55 -04:00
|
|
|
if isRepeatable
|
2014-05-31 17:55:26 -04:00
|
|
|
log.debug 'Upserting repeatable achievement called \'' + (achievement.get 'name') + '\' for ' + userID
|
2014-05-19 19:25:41 -04:00
|
|
|
proportionalTo = achievement.get 'proportionalTo'
|
2014-05-22 10:59:01 -04:00
|
|
|
originalAmount = util.getByPath(originalDocObj, proportionalTo) or 0
|
2014-05-31 17:19:55 -04:00
|
|
|
newAmount = docObj[proportionalTo]
|
2014-05-19 19:25:41 -04:00
|
|
|
|
2014-05-22 10:59:01 -04:00
|
|
|
if originalAmount isnt newAmount
|
2014-05-19 19:25:41 -04:00
|
|
|
earned.notified = false
|
2014-05-22 10:59:01 -04:00
|
|
|
earned.achievedAmount = newAmount
|
2014-05-19 19:25:41 -04:00
|
|
|
earned.changed = Date.now()
|
2014-05-26 12:21:56 -04:00
|
|
|
EarnedAchievement.findOneAndUpdate({achievement:earned.achievement, user:earned.user}, earned, upsert:true, (err, docs) ->
|
2014-05-31 17:55:26 -04:00
|
|
|
return log.debug err if err?
|
2014-05-26 12:21:56 -04:00
|
|
|
)
|
|
|
|
|
|
|
|
earnedPoints = achievement.get('worth') * (newAmount - originalAmount)
|
|
|
|
wrapUp()
|
|
|
|
|
2014-05-22 10:59:01 -04:00
|
|
|
else # not alreadyAchieved
|
2014-05-31 17:55:26 -04:00
|
|
|
log.debug 'Creating a new earned achievement called \'' + (achievement.get 'name') + '\' for ' + userID
|
2014-05-19 19:25:41 -04:00
|
|
|
(new EarnedAchievement(earned)).save (err, doc) ->
|
2014-05-31 17:55:26 -04:00
|
|
|
return log.debug err if err?
|
2014-05-26 12:21:56 -04:00
|
|
|
|
|
|
|
earnedPoints = achievement.get('worth')
|
|
|
|
wrapUp()
|
|
|
|
|
2014-05-18 07:21:27 -04:00
|
|
|
delete before[doc.id] unless isNew # This assumes everything we patch has a _id
|
2014-05-31 17:19:55 -04:00
|
|
|
return
|