mongoose = require 'mongoose' jsonschema = require '../../app/schemas/models/achievement' log = require 'winston' utils = require '../../app/core/utils' plugins = require('../plugins/plugins') AchievablePlugin = require '../plugins/achievements' TreemaUtils = require '../../bower_components/treema/treema-utils.js' config = require '../../server_config' co = require 'co' # `pre` and `post` are not called for update operations executed directly on the database, # including `Model.update`,`.findByIdAndUpdate`,`.findOneAndUpdate`, `.findOneAndRemove`,and `.findByIdAndRemove`.order # to utilize `pre` or `post` middleware, you should `find()` the document, and call the `init`, `validate`, `save`, # or `remove` functions on the document. See [explanation](http://github.com/LearnBoost/mongoose/issues/964). AchievementSchema = new mongoose.Schema({ userField: String }, {strict: false,read: config.mongo.readpref}) AchievementSchema.index( { _fts: 'text' _ftsx: 1 }, { name: 'search index' sparse: true weights: {name: 1} default_language: 'english' 'language_override': 'language' 'textIndexVersion': 2 }) AchievementSchema.index({i18nCoverage: 1}, {name: 'translation coverage index', sparse: true}) AchievementSchema.index({slug: 1}, {name: 'slug index', sparse: true, unique: true}) AchievementSchema.index({related: 1}, {name: 'related index', sparse: true}) AchievementSchema.index({updated: 1}, {name: 'updated index'}) AchievementSchema.methods.objectifyQuery = -> try @set('query', JSON.parse(@get('query'))) if typeof @get('query') == 'string' catch error log.error "Couldn't convert query string to object because of #{error}" @set('query', {}) AchievementSchema.methods.stringifyQuery = -> @set('query', JSON.stringify(@get('query'))) if typeof @get('query') != 'string' AchievementSchema.methods.getExpFunction = -> func = @get('function') ? {} TreemaUtils.populateDefaults(func, jsonschema.properties.function) return utils.functionCreators[func.kind](func.parameters) if func.kind of utils.functionCreators AchievementSchema.statics.jsonschema = jsonschema AchievementSchema.statics.achievementCollections = {} # Reloads all achievements into memory. # TODO might want to tweak this to only load new achievements AchievementSchema.statics.loadAchievements = co.wrap -> AchievementSchema.statics.resetAchievements() t0 = new Date() Achievement = require('./Achievement') achievements = yield Achievement.find({collection: {$ne: 'level.sessions'}}) return if t0 < @lastReset # if a test has run resetAchievements during the fetch, abort for achievement in achievements collection = achievement.get 'collection' AchievementSchema.statics.achievementCollections[collection] ?= [] if _.find AchievementSchema.statics.achievementCollections[collection], ((a) -> a.get('_id').toHexString() is achievement.get('_id').toHexString()) log.warn "Uh oh, we tried to add another copy of the same achievement #{achievement.get('_id')} #{achievement.get('name')} to the #{collection} achievement list..." else AchievementSchema.statics.achievementCollections[collection].push achievement unless achievement.get('query') log.error "Uh oh, there is an achievement with an empty query: #{achievement}" return AchievementSchema.statics.achievementCollections AchievementSchema.statics.getLoadedAchievements = -> AchievementSchema.statics.achievementCollections AchievementSchema.statics.resetAchievements = -> delete AchievementSchema.statics.achievementCollections[collection] for collection of AchievementSchema.statics.achievementCollections @lastReset = new Date() AchievementSchema.statics.editableProperties = [ 'name' 'query' 'worth' 'collection' 'description' 'userField' 'proportionalTo' 'icon' 'function' 'related' 'difficulty' 'category' 'rewards' 'i18n' 'i18nCoverage' 'hidden' ] AchievementSchema.statics.postEditableProperties = [] AchievementSchema.statics.jsonSchema = require '../../app/schemas/models/achievement' # Queries are stored as JSON strings, objectify them upon loading AchievementSchema.post 'init', (doc) -> doc.objectifyQuery() AchievementSchema.pre 'save', (next) -> @stringifyQuery() if not @get('updated') @set('updated', new Date().toISOString()) next() # Reload achievements upon save # This is going to basically not work when there is more than one application server, right? AchievementSchema.post 'save', -> @constructor.loadAchievements() AchievementSchema.plugin(plugins.NamedPlugin) AchievementSchema.plugin(plugins.SearchablePlugin, {searchable: ['name']}) AchievementSchema.plugin plugins.TranslationCoveragePlugin AchievementSchema.plugin plugins.PatchablePlugin module.exports = Achievement = mongoose.model('Achievement', AchievementSchema, 'achievements') AchievementSchema.statics.loadAchievements()