2014-06-30 22:16:26 -04:00
|
|
|
mongoose = require 'mongoose'
|
2014-05-18 07:21:27 -04:00
|
|
|
EarnedAchievement = require '../achievements/EarnedAchievement'
|
|
|
|
LocalMongo = require '../../app/lib/LocalMongo'
|
2014-11-28 20:49:41 -05:00
|
|
|
util = require '../../app/core/utils'
|
2014-05-31 17:55:26 -04:00
|
|
|
log = require 'winston'
|
2014-05-13 16:46:56 -04:00
|
|
|
|
2014-06-14 14:12:17 -04:00
|
|
|
# Warning: To ensure proper functioning one must always `find` documents before saving them.
|
|
|
|
# Otherwise the schema's `post init` won't be triggered and the plugin can't keep track of changes
|
|
|
|
# TODO if this is still a common scenario I could implement a database hit after all, but only
|
|
|
|
# on the condition that it's necessary and still not too frequent in occurrence
|
2014-06-14 09:34:23 -04:00
|
|
|
AchievablePlugin = (schema, options) ->
|
2014-06-10 14:05:32 -04:00
|
|
|
User = require '../users/User' # Avoid mutual inclusion cycles
|
2014-07-05 02:18:21 -04:00
|
|
|
Achievement = require '../achievements/Achievement'
|
2014-06-09 06:26:47 -04:00
|
|
|
|
2014-05-18 07:21:27 -04:00
|
|
|
before = {}
|
2014-05-13 16:46:56 -04:00
|
|
|
|
2014-07-03 15:20:06 -04:00
|
|
|
# Keep track the document before it's saved
|
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-06-14 14:12:17 -04:00
|
|
|
# TODO check out how many objects go unreleased
|
2014-05-18 11:24:21 -04:00
|
|
|
|
2014-07-03 15:20:06 -04:00
|
|
|
# Check if an achievement has been earned
|
2014-05-13 16:46:56 -04:00
|
|
|
schema.post 'save', (doc) ->
|
2014-11-25 15:43:17 -05:00
|
|
|
# sometimes post appears to be called twice. Handle this...
|
|
|
|
# TODO: Refactor this system to make it request-specific,
|
|
|
|
# perhaps by having POST/PUT requests store the copy on the request object themselves.
|
|
|
|
return if doc.isInit('_id') and not (doc.id of before)
|
2014-06-14 14:12:17 -04:00
|
|
|
isNew = not doc.isInit('_id') or not (doc.id of before)
|
2014-05-18 13:58:30 -04:00
|
|
|
originalDocObj = before[doc.id] unless isNew
|
2014-05-18 07:21:27 -04:00
|
|
|
|
2014-06-14 14:12:17 -04:00
|
|
|
if doc.isInit('_id') and not doc.id of before
|
|
|
|
log.warn 'document was already initialized but did not go through `init` and is therefore treated as new while it might not be'
|
|
|
|
|
2014-06-24 07:49:54 -04:00
|
|
|
category = doc.constructor.collection.name
|
2014-06-14 09:34:23 -04:00
|
|
|
loadedAchievements = Achievement.getLoadedAchievements()
|
2014-06-14 14:12:17 -04:00
|
|
|
#log.debug 'about to save ' + category + ', number of achievements is ' + Object.keys(loadedAchievements).length
|
2014-05-18 07:21:27 -04:00
|
|
|
|
2014-06-14 09:34:23 -04:00
|
|
|
if category of loadedAchievements
|
2014-05-18 07:21:27 -04:00
|
|
|
docObj = doc.toObject()
|
2014-06-14 09:34:23 -04:00
|
|
|
for achievement in loadedAchievements[category]
|
2014-09-30 19:18:32 -04:00
|
|
|
do (achievement) ->
|
|
|
|
query = achievement.get('query')
|
2014-11-17 11:44:53 -05:00
|
|
|
return log.warn("Empty achievement query for #{achievement.get('name')}.") if _.isEmpty query
|
2014-09-30 19:18:32 -04:00
|
|
|
isRepeatable = achievement.get('proportionalTo')?
|
|
|
|
alreadyAchieved = if isNew then false else LocalMongo.matchesQuery originalDocObj, query
|
|
|
|
newlyAchieved = LocalMongo.matchesQuery(docObj, query)
|
2014-11-21 01:08:49 -05:00
|
|
|
return unless newlyAchieved and (not alreadyAchieved or isRepeatable)
|
|
|
|
EarnedAchievement.createForAchievement(achievement, doc, originalDocObj)
|
2014-05-26 12:21:56 -04:00
|
|
|
|
2014-06-14 14:12:17 -04:00
|
|
|
delete before[doc.id] if doc.id of before
|
2014-06-10 14:05:32 -04:00
|
|
|
|
2014-06-14 09:34:23 -04:00
|
|
|
module.exports = AchievablePlugin
|