Refactor rest of /db/campaign routes

For 
This commit is contained in:
Scott Erickson 2016-05-04 12:05:28 -07:00
parent 4827dc57e7
commit b125f9b2fa
9 changed files with 313 additions and 293 deletions

View file

@ -6,7 +6,6 @@ module.exports.handlers =
# TODO: Disabling this until we know why our app servers CPU grows out of control.
# 'analytics_users_active': 'handlers/analytics_users_active_handler'
'article': 'handlers/article_handler'
'campaign': 'handlers/campaign_handler'
'clan': 'handlers/clan_handler'
'classroom': 'handlers/classroom_handler'
'course': 'handlers/course_handler'

View file

@ -1,115 +0,0 @@
Campaign = require './../models/Campaign'
Level = require '../models/Level'
Achievement = require '../models/Achievement'
Handler = require '../commons/Handler'
async = require 'async'
mongoose = require 'mongoose'
CampaignHandler = class CampaignHandler extends Handler
modelClass: Campaign
jsonSchema: require '../../app/schemas/models/campaign.schema'
hasAccess: (req) ->
req.method in ['GET'] 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.
query = {}
projection = {}
if @modelClass.schema.uses_coco_translation_coverage and req.query.view is 'i18n-coverage'
query = i18nCoverage: {$exists: true}
if req.query.project
projection[field] = 1 for field in req.query.project.split(',')
if req.query.type
query.type = req.query.type
q = @modelClass.find query, projection
q.exec (err, documents) =>
return @sendDatabaseError(res, err) if err
documents = (@formatEntity(req, doc) for doc in documents)
@sendSuccess(res, documents)
getOverworld: (req, res) ->
return @sendForbiddenError(res) if not @hasAccess(req)
projection = {}
if req.query.project
projection[field] = 1 for field in req.query.project.split(',')
q = @modelClass.find {type: 'hero'}, projection
q.exec (err, documents) =>
return @sendDatabaseError(res, err) if err
formatCampaign = (doc) =>
obj = @formatEntity(req, doc)
obj.adjacentCampaigns = _.mapValues(obj.adjacentCampaigns, (a) -> _.pick(a, ['showIfUnlocked', 'color', 'name', 'description' ]))
for original, level of obj.levels
obj.levels[original] = _.pick level, ['locked', 'disabled', 'original', 'rewards', 'slug']
obj
documents = (formatCampaign(doc) for doc in documents)
@sendSuccess(res, documents)
getByRelationship: (req, res, args...) ->
relationship = args[1]
return @getOverworld(req,res) if args[0] is '-' and relationship is 'overworld'
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))
getNamesByIDs: (req, res) -> @getNamesByOriginals req, res, true
module.exports = new CampaignHandler()

View file

@ -7,6 +7,8 @@ mongoose = require 'mongoose'
Campaign = require '../models/Campaign'
parse = require '../commons/parse'
LevelSession = require '../models/LevelSession'
Achievement = require '../models/Achievement'
Level = require '../models/Level'
slack = require '../slack'
module.exports =
@ -39,3 +41,42 @@ module.exports =
res.status(200).send(campaign.toObject())
docLink = "http://codecombat.com#{req.headers['x-current-path']}"
slack.sendChangedSlackMessage creator: req.user, target: campaign, docLink: docLink
fetchRelatedAchievements: wrap (req, res) ->
campaign = yield database.getDocFromHandle(req, Campaign)
if not campaign
throw new errors.NotFound('Campaign not found.')
levels = campaign.get('levels') or []
project = parse.getProjectFromReq(req)
fetches = []
for level in _.values(levels)
fetches.push Achievement.find({ related: level.original }).select(project)
achievementses = yield fetches
achievements = _.flatten(achievementses)
res.status(200).send((achievement.toObject({req: req}) for achievement in achievements))
fetchRelatedLevels: wrap (req, res) ->
campaign = yield database.getDocFromHandle(req, Campaign)
if not campaign
throw new errors.NotFound('Campaign not found.')
levels = campaign.get('levels') or []
project = parse.getProjectFromReq(req)
sort = { 'version.major': -1, 'version.minor': -1 }
fetches = []
for level in _.values(levels)
query = { original: mongoose.Types.ObjectId(level.original) }
fetches.push Level.findOne(query).sort(sort).select(project)
levels = yield fetches
res.status(200).send((level.toObject({req: req}) for level in levels))
fetchOverworld: wrap (req, res) ->
project = parse.getProjectFromReq(req)
campaigns = yield Campaign.find({type: 'hero'}).select(project)
formatCampaign = (campaign) ->
campaign.toObject({req: req})
campaign.adjacentCampaigns = _.mapValues(campaign.adjacentCampaigns, (a) ->
_.pick(a, ['showIfUnlocked', 'color', 'name', 'description' ]))
for original, level of campaign.levels
campaign.levels[original] = _.pick level, ['locked', 'disabled', 'original', 'rewards', 'slug']
return campaign
res.status(200).send((formatCampaign(campaign) for campaign in campaigns))

View file

@ -42,8 +42,17 @@ module.exports.setup = (app) ->
app.post('/db/article/:handle/watchers', mw.patchable.joinWatchers(Article))
app.delete('/db/article/:handle/watchers', mw.patchable.leaveWatchers(Article))
app.get('/db/campaign', mw.campaigns.fetchByType)
Campaign = require '../models/Campaign'
app.post('/db/campaign', mw.auth.checkHasPermission(['admin']), mw.rest.post(Campaign))
app.get('/db/campaign', mw.campaigns.fetchByType, mw.rest.get(Campaign))
app.get('/db/campaign/names', mw.named.names(Campaign))
app.post('/db/campaign/names', mw.named.names(Campaign))
app.get('/db/campaign/:handle', mw.rest.getByHandle(Campaign))
app.put('/db/campaign/:handle', mw.campaigns.put)
app.get('/db/campaign/:handle/achievements', mw.campaigns.fetchRelatedAchievements)
app.get('/db/campaign/:handle/levels', mw.campaigns.fetchRelatedLevels)
app.get('/db/campaign/:handle/patches', mw.patchable.patches(Campaign))
app.get('/db/campaign/-/overworld', mw.campaigns.fetchOverworld)
app.post('/db/classroom', mw.classrooms.post)
app.get('/db/classroom', mw.classrooms.getByOwner)

View file

@ -0,0 +1,204 @@
require '../common'
campaignURL = getURL('/db/campaign')
campaignSchema = require '../../../app/schemas/models/campaign.schema'
campaignLevelProperties = _.keys(campaignSchema.properties.levels.additionalProperties.properties)
Achievement = require '../../../server/models/Achievement'
Campaign = require '../../../server/models/Campaign'
Level = require '../../../server/models/Level'
User = require '../../../server/models/User'
request = require '../request'
utils = require '../utils'
slack = require '../../../server/slack'
Promise = require 'bluebird'
describe 'GET /db/campaign', ->
beforeEach utils.wrap (done) ->
yield utils.clearModels([Campaign])
@heroCampaign1 = yield new Campaign({name: 'Hero Campaign 1', type: 'hero'}).save()
@heroCampaign2 = yield new Campaign({name: 'Hero Campaign 2', type: 'hero'}).save()
@courseCampaign1 = yield new Campaign({name: 'Course Campaign 1', type: 'course'}).save()
@courseCampaign2 = yield new Campaign({name: 'Course Campaign 2', type: 'course'}).save()
done()
it 'returns all campaigns', utils.wrap (done) ->
[res, body] = yield request.getAsync getURL('/db/campaign'), { json: true }
expect(res.statusCode).toBe(200)
expect(body.length).toBe(4)
done()
describe 'with GET query param type', ->
it 'returns campaigns of that type', utils.wrap (done) ->
[res, body] = yield request.getAsync getURL('/db/campaign?type=course'), { json: true }
expect(res.statusCode).toBe(200)
expect(body.length).toBe(2)
for campaign in body
expect(campaign.type).toBe('course')
done()
describe 'POST /db/campaign', ->
beforeEach utils.wrap (done) ->
yield utils.clearModels [Campaign, Level, User]
admin = yield utils.initAdmin()
yield utils.loginUser(admin)
@levels = (level.toObject() for level in [yield utils.makeLevel(), yield utils.makeLevel()])
done()
it 'can create campaigns', utils.wrap (done) ->
campaign = {
levels: {}
}
for level in @levels.reverse()
campaign.levels[level.original.valueOf()] = _.pick level, campaignLevelProperties
[res, body] = yield request.postAsync {uri: campaignURL, json: campaign}
expect(res.statusCode).toBe(201)
campaign = body
done()
describe 'PUT /db/campaign/:handle', ->
beforeEach utils.wrap (done) ->
yield utils.clearModels [Achievement, Campaign, Level, User]
admin = yield utils.initAdmin()
yield utils.loginUser(admin)
@campaign = yield utils.makeCampaign()
@levelsUpdated = @campaign.get('levelsUpdated').toISOString()
done()
it 'saves changes to campaigns', utils.wrap (done) ->
[res, body] = yield request.putAsync { uri: campaignURL+'/'+@campaign.id, json: { name: 'A new name' } }
expect(body.name).toBe('A new name')
c = yield Campaign.findById(body._id)
expect(c.get('name')).toBe('A new name')
done()
it 'does not allow normal users to make changes', utils.wrap (done) ->
user = yield utils.initUser()
yield utils.loginUser(user)
[res, body] = yield request.putAsync { uri: campaignURL+'/'+@campaign.id, json: { name: 'A new name' } }
expect(res.statusCode).toBe(403)
done()
it 'allows normal users to put translation changes', utils.wrap (done) ->
user = yield utils.initUser()
yield utils.logout()
yield utils.loginUser(user)
json = _.clone @campaign.toObject()
json.i18n = { de: { name: 'A new name' } }
[res, body] = yield request.putAsync { uri: campaignURL+'/'+@campaign.id, json: json }
expect(res.statusCode).toBe(200)
done()
it 'sends a slack message', utils.wrap (done) ->
spyOn(slack, 'sendSlackMessage')
[res, body] = yield request.putAsync { uri: campaignURL+'/'+@campaign.id, json: { name: 'A new name' } }
expect(slack.sendSlackMessage).toHaveBeenCalled()
done()
it 'sets campaign.levelsUpdated to now iff levels are changed', utils.wrap (done) ->
data = {name: 'whatever'}
[res, body] = yield request.putAsync { uri: campaignURL+'/'+@campaign.id, json: data }
expect(body.levelsUpdated).toBe(@levelsUpdated)
yield new Promise((resolve) -> setTimeout(resolve, 10))
data = {levels: {'a': {original: 'a'}}}
[res, body] = yield request.putAsync { uri: campaignURL+'/'+@campaign.id, json: data }
expect(body.levelsUpdated).not.toBe(@levelsUpdated)
done()
describe 'GET, POST /db/campaign/names', ->
beforeEach utils.wrap (done) ->
yield utils.clearModels [Achievement, Campaign, Level, User]
admin = yield utils.initAdmin()
yield utils.loginUser(admin)
@campaignA = yield utils.makeCampaign()
@campaignB = yield utils.makeCampaign()
done()
it 'returns names of campaigns by for given ids', utils.wrap (done) ->
[res, body] = yield request.getAsync({url: getURL("/db/campaign/names?ids=#{@campaignA.id},#{@campaignB.id}"), json: true})
expect(res.statusCode).toBe(200)
expect(body.length).toBe(2)
[res, body] = yield request.postAsync({url: getURL('/db/campaign/names'), json: { ids: [@campaignA.id, @campaignB.id] }})
expect(res.statusCode).toBe(200)
expect(body.length).toBe(2)
done()
describe 'GET /db/campaign/:handle/levels', ->
beforeEach utils.wrap (done) ->
yield utils.clearModels [Campaign, Level, User]
admin = yield utils.initAdmin()
yield utils.loginUser(admin)
@level1 = yield utils.makeLevel()
@level2 = yield utils.makeLevel()
@campaign = yield utils.makeCampaign({}, {levels: [@level1, @level2]})
done()
it 'fetches the levels in a campaign', utils.wrap (done) ->
url = getURL("/db/campaign/#{@campaign._id}/levels")
[res, body] = yield request.getAsync {uri: url, json: true}
expect(res.statusCode).toBe(200)
expect(body.length).toBe(2)
expect(_.difference([@level1.get('slug'), @level2.get('slug')], _.pluck(body, 'slug')).length).toBe(0)
done()
describe 'GET /db/campaign/:handle/achievements', ->
beforeEach utils.wrap (done) ->
yield utils.clearModels [Achievement, Campaign, Level, User]
admin = yield utils.initAdmin()
yield utils.loginUser(admin)
level = yield utils.makeLevel()
@achievement = yield utils.makeAchievement({}, {related: level})
@campaign = yield utils.makeCampaign({}, {levels: [level]})
done()
it 'fetches the achievements in the levels in a campaign', utils.wrap (done) ->
url = getURL("/db/campaign/#{@campaign.id}/achievements")
[res, body] = yield request.getAsync {uri: url, json: true}
expect(res.statusCode).toBe(200)
expect(body.length).toBe(1)
done()
describe 'GET /db/campaign/-/overworld', ->
beforeEach utils.wrap (done) ->
yield utils.clearModels [Campaign, Level, User]
admin = yield utils.initAdmin()
yield utils.loginUser(admin)
level = yield utils.makeLevel()
@campaignA = yield utils.makeCampaign({type: 'hero', hidesHUD: true})
@campaignB = yield utils.makeCampaign({type: 'hero'}, {
levels: [level]
adjacentCampaigns: [@campaignA]
})
@campaignC = yield utils.makeCampaign({type: 'course'})
done()
it 'fetches campaigns of type "hero", returning projected level and adjacentCampaign children', utils.wrap (done) ->
url = getURL("/db/campaign/-/overworld")
[res, body] = yield request.getAsync {uri: url, json: true}
expect(res.statusCode).toBe(200)
expect(body.length).toBe(2)
for campaign in body
expect(campaign.type).toBe('hero')
campaign = _.findWhere(body, {_id: @campaignB.id})
expect(_.size(campaign.levels)).toBeGreaterThan(0)
for level in _.values(campaign.levels)
expect(level.slug).toBeDefined()
expect(_.size(campaign.adjacentCampaigns)).toBeGreaterThan(0)
for campaign in _.values(campaign.adjacentCampaigns)
expect(campaign.name).toBeDefined()
done()
it 'takes a project query param', utils.wrap (done) ->
url = getURL("/db/campaign/-/overworld?project=name")
[res, body] = yield request.getAsync {uri: url, json: true}
expect(res.statusCode).toBe(200)
expect(body.length).toBe(2)
for campaign in body
expect(campaign.type).toBeUndefined()
expect(campaign.name).toBeDefined()
done()

View file

@ -1,134 +0,0 @@
require '../common'
levels = [
{
name: 'Level 1'
description: 'This is the first level.'
disableSpaces: true
icon: 'somestringyoudontneed.png'
}
{
name: 'Level 2'
description: 'This is the second level.'
requiresSubscription: true
backspaceThrottle: true
}
]
achievement = {
name: 'Level 1 Complete'
}
campaign = {
name: 'Campaign'
levels: {}
i18n: {}
}
levelURL = getURL('/db/level')
achievementURL = getURL('/db/achievement')
campaignURL = getURL('/db/campaign')
campaignSchema = require '../../../app/schemas/models/campaign.schema'
campaignLevelProperties = _.keys(campaignSchema.properties.levels.additionalProperties.properties)
Achievement = require '../../../server/models/Achievement'
Campaign = require '../../../server/models/Campaign'
Level = require '../../../server/models/Level'
User = require '../../../server/models/User'
request = require '../request'
utils = require '../utils'
slack = require '../../../server/slack'
Promise = require 'bluebird'
describe 'PUT /db/campaign', ->
beforeEach utils.wrap (done) ->
yield utils.clearModels [Achievement, Campaign, Level, User]
admin = yield utils.initAdmin()
yield utils.loginUser(admin)
[res, body] = yield request.postAsync { uri: campaignURL, json: campaign }
@levelsUpdated = body.levelsUpdated
@campaign = yield Campaign.findById(body._id)
done()
it 'saves changes to campaigns', utils.wrap (done) ->
[res, body] = yield request.putAsync { uri: campaignURL+'/'+@campaign.id, json: { name: 'A new name' } }
expect(body.name).toBe('A new name')
c = yield Campaign.findById(body._id)
expect(c.get('name')).toBe('A new name')
done()
it 'does not allow normal users to make changes', utils.wrap (done) ->
user = yield utils.initUser()
yield utils.loginUser(user)
[res, body] = yield request.putAsync { uri: campaignURL+'/'+@campaign.id, json: { name: 'A new name' } }
expect(res.statusCode).toBe(403)
done()
it 'allows normal users to put translation changes', utils.wrap (done) ->
user = yield utils.initUser()
yield utils.loginUser(user)
json = _.clone @campaign.toObject()
json.i18n = { de: { name: 'A new name' } }
[res, body] = yield request.putAsync { uri: campaignURL+'/'+@campaign.id, json: json }
expect(res.statusCode).toBe(200)
done()
it 'sends a slack message', utils.wrap (done) ->
spyOn(slack, 'sendSlackMessage')
[res, body] = yield request.putAsync { uri: campaignURL+'/'+@campaign.id, json: { name: 'A new name' } }
expect(slack.sendSlackMessage).toHaveBeenCalled()
done()
it 'sets campaign.levelsUpdated to now iff levels are changed', utils.wrap (done) ->
data = {name: 'whatever'}
[res, body] = yield request.putAsync { uri: campaignURL+'/'+@campaign.id, json: data }
expect(body.levelsUpdated).toBe(@levelsUpdated)
yield new Promise((resolve) -> setTimeout(resolve, 10))
data = {levels: {'a': {original: 'a'}}}
[res, body] = yield request.putAsync { uri: campaignURL+'/'+@campaign.id, json: data }
expect(body.levelsUpdated).not.toBe(@levelsUpdated)
done()
describe '/db/campaign', ->
it 'prepares the db first', (done) ->
clearModels [Achievement, Campaign, Level, User], (err) ->
expect(err).toBeNull()
loginAdmin (admin) ->
levels[0].permissions = levels[1].permissions = [{target: admin._id, access: 'owner'}]
request.post {uri: levelURL, json: levels[0]}, (err, res, body) ->
expect(res.statusCode).toBe(200)
levels[0] = body
request.post {uri: levelURL, json: levels[1]}, (err, res, body) ->
expect(res.statusCode).toBe(200)
levels[1] = body
achievement.related = levels[0].original
achievement.rewards = { levels: [levels[1].original] }
request.post {uri: achievementURL, json: achievement}, (err, res, body) ->
achievement = body
done()
it 'can create campaigns', (done) ->
for level in levels.reverse()
campaign.levels[level.original] = _.pick level, campaignLevelProperties
request.post {uri: campaignURL, json: campaign}, (err, res, body) ->
expect(res.statusCode).toBe(200)
campaign = body
done()
describe '/db/campaign/.../levels', ->
it 'fetches the levels in a campaign', (done) ->
url = getURL("/db/campaign/#{campaign._id}/levels")
request.get {uri: url}, (err, res, body) ->
expect(res.statusCode).toBe(200)
body = JSON.parse(body)
expect(body.length).toBe(2)
expect(_.difference(['level-1', 'level-2'],(level.slug for level in body)).length).toBe(0)
done()
describe '/db/campaign/.../achievements', ->
it 'fetches the achievements in the levels in a campaign', (done) ->
url = getURL("/db/campaign/#{campaign._id}/achievements")
request.get {uri: url}, (err, res, body) ->
expect(res.statusCode).toBe(200)
body = JSON.parse(body)
expect(body.length).toBe(1)
done()

View file

@ -1,38 +0,0 @@
config = require '../../../server_config'
require '../common'
clientUtils = require '../../../app/core/utils' # Must come after require /common
utils = require '../utils'
_ = require 'lodash'
Promise = require 'bluebird'
request = require '../request'
requestAsync = Promise.promisify(request, {multiArgs: true})
campaignURL = getURL('/db/campaign')
Campaign = require '../../../server/models/Campaign'
describe '/db/campaign', ->
beforeEach utils.wrap (done) ->
yield utils.clearModels([Campaign])
@heroCampaign1 = yield new Campaign({name: 'Hero Campaign 1', type: 'hero'}).save()
@heroCampaign2 = yield new Campaign({name: 'Hero Campaign 2', type: 'hero'}).save()
@courseCampaign1 = yield new Campaign({name: 'Course Campaign 1', type: 'course'}).save()
@courseCampaign2 = yield new Campaign({name: 'Course Campaign 2', type: 'course'}).save()
done()
describe 'GET campaigns of a certain type', ->
it 'returns only that type', utils.wrap (done) ->
[res, body] = yield request.getAsync getURL('/db/campaign?type=course'), { json: true }
expect(res.statusCode).toBe(200)
expect(body.length).toBe(2)
for campaign in body
expect(campaign.type).toBe('course')
done()
describe 'GET all campaigns', ->
it 'returns all of them regardless of type', utils.wrap (done) ->
[res, body] = yield request.getAsync getURL('/db/campaign'), { json: true }
expect(res.statusCode).toBe(200)
expect(body.length).toBe(4)
done()

View file

@ -20,7 +20,7 @@ describe 'Level', ->
urlLevel = '/db/level'
it 'clears things first', (done) ->
clearModels [Level], (err) ->
clearModels [Level, User], (err) ->
expect(err).toBeNull()
done()

View file

@ -3,7 +3,12 @@ utils = require '../../server/lib/utils'
co = require 'co'
Promise = require 'bluebird'
User = require '../../server/models/User'
Level = require '../../server/models/Level'
Achievement = require '../../server/models/Achievement'
Campaign = require '../../server/models/Campaign'
campaignSchema = require '../../app/schemas/models/campaign.schema'
campaignLevelProperties = _.keys(campaignSchema.properties.levels.additionalProperties.properties)
campaignAdjacentCampaignProperties = _.keys(campaignSchema.properties.adjacentCampaigns.additionalProperties.properties)
module.exports = mw =
getURL: (path) -> 'http://localhost:3001' + path
@ -32,7 +37,7 @@ module.exports = mw =
promise = user.save()
return promise
loginUser: Promise.promisify (user, options={}, done) ->
loginUser: Promise.promisify (user, options={}, done) ->
if _.isFunction(options)
done = options
options = {}
@ -43,6 +48,7 @@ module.exports = mw =
(options.request or request).post mw.getURL('/auth/login'), { form: form }, (err, res) ->
expect(err).toBe(null)
expect(res.statusCode).toBe(200)
mw.lastLogin = user
done(err, user)
initAdmin: (options) ->
@ -70,4 +76,52 @@ module.exports = mw =
fn = co.wrap(gen)
return (done) ->
fn.apply(@, [done]).catch (err) -> done.fail(err)
makeLevel: Promise.promisify (data, sources, done) ->
args = Array.from(arguments)
[done, [data, sources]] = [args.pop(), args]
data = _.extend({}, {
name: _.uniqueId('Level ')
permissions: [{target: mw.lastLogin.id, access: 'owner'}]
}, data)
request.post { uri: getURL('/db/level'), json: data }, (err, res) ->
return done(err) if err
Level.findById(res.body._id).exec done
makeAchievement: Promise.promisify (data, sources, done) ->
args = Array.from(arguments)
[done, [data, sources]] = [args.pop(), args]
data = _.extend({}, {
name: _.uniqueId('Achievement ')
}, data)
if sources.related and not data.related
related = sources.related
data.related = (related.get('original') or related._id).valueOf()
request.post { uri: getURL('/db/achievement'), json: data }, (err, res) ->
return done(err) if err
Achievement.findById(res.body._id).exec done
makeCampaign: Promise.promisify (data, sources, done) ->
args = Array.from(arguments)
[done, [data, sources]] = [args.pop(), args]
data = _.extend({}, {
name: _.uniqueId('Campaign ')
}, data)
if not data.levels
data.levels = {}
for level in sources?.levels or []
data.levels[level.get('original').valueOf()] = _.pick level.toObject(), campaignLevelProperties
if not data.adjacentCampaigns
data.adjacentCampaigns = {}
for campaign in sources?.adjacentCampaigns or []
data.adjacentCampaigns[campaign.id] = _.pick campaign.toObject(), campaignAdjacentCampaignProperties
request.post { uri: getURL('/db/campaign'), json: data }, (err, res) ->
return done(err) if err
Campaign.findById(res.body._id).exec done