codecombat/server/campaigns/campaign_handler.coffee

105 lines
3.8 KiB
CoffeeScript

Campaign = require './Campaign'
Level = require '../levels/Level'
Achievement = require '../achievements/Achievement'
Handler = require '../commons/Handler'
async = require 'async'
mongoose = require 'mongoose'
CampaignHandler = class CampaignHandler extends Handler
modelClass: Campaign
editableProperties: [
'name'
'fullName'
'description'
'i18n'
'i18nCoverage'
'ambientSound'
'backgroundImage'
'backgroundColor'
'backgroundColorTransparent'
'adjacentCampaigns'
'levels'
]
jsonSchema: require '../../app/schemas/models/campaign.schema'
hasAccess: (req) ->
req.method in ['GET', 'PUT'] or req.user?.isAdmin()
hasAccessToDocument: (req, document, method=null) ->
return true if req.user?.isAdmin()
if @modelClass.schema.uses_coco_translation_coverage and (method or req.method).toLowerCase() in ['post', 'put']
return true if @isJustFillingTranslations(req, document)
if req.method is 'GET'
return true
return false
get: (req, res) ->
return @sendForbiddenError(res) if not @hasAccess(req)
# We don't have normal text search or anything set up to make /db/campaign work, so we'll just give them all campaigns, no problem.
q = @modelClass.find {}
q.exec (err, documents) =>
return @sendDatabaseError(res, err) if err
documents = (@formatEntity(req, doc) for doc in documents)
@sendSuccess(res, documents)
getByRelationship: (req, res, args...) ->
relationship = args[1]
if relationship in ['levels', 'achievements']
projection = {}
if req.query.project
projection[field] = 1 for field in req.query.project.split(',')
@getDocumentForIdOrSlug args[0], (err, campaign) =>
return @sendDatabaseError(res, err) if err
return @sendNotFoundError(res) unless campaign?
return @getRelatedLevels(req, res, campaign, projection) if relationship is 'levels'
return @getRelatedAchievements(req, res, campaign, projection) if relationship is 'achievements'
else
super(arguments...)
getRelatedLevels: (req, res, campaign, projection) ->
extraProjectionProps = []
unless _.isEmpty(projection)
# Make sure that permissions and version are fetched, but not sent back if they didn't ask for them.
extraProjectionProps.push 'permissions' unless projection.permissions
extraProjectionProps.push 'version' unless projection.version
projection.permissions = 1
projection.version = 1
levels = campaign.get('levels') or []
f = (levelOriginal) ->
(callback) ->
query = { original: mongoose.Types.ObjectId(levelOriginal) }
sort = { 'version.major': -1, 'version.minor': -1 }
Level.findOne(query, projection).sort(sort).exec callback
fetches = (f(level.original) for level in _.values(levels))
async.parallel fetches, (err, levels) =>
return @sendDatabaseError(res, err) if err
filteredLevels = (_.omit(level.toObject(), extraProjectionProps) for level in levels)
return @sendSuccess(res, filteredLevels)
getRelatedAchievements: (req, res, campaign, projection) ->
levels = campaign.get('levels') or []
f = (levelOriginal) ->
(callback) ->
query = { related: levelOriginal }
Achievement.find(query, projection).exec callback
fetches = (f(level.original) for level in _.values(levels))
async.parallel fetches, (err, achievementses) =>
achievements = _.flatten(achievementses)
return @sendDatabaseError(res, err) if err
return @sendSuccess(res, (achievement.toObject() for achievement in achievements))
onPutSuccess: (req, doc) ->
docLink = "http://codecombat.com#{req.headers['x-current-path']}"
@sendChangedHipChatMessage creator: req.user, target: doc, docLink: docLink
getNamesByIDs: (req, res) -> @getNamesByOriginals req, res, true
module.exports = new CampaignHandler()