Merge branch 'master' of github.com:codecombat/codecombat

This commit is contained in:
iAladdin 2014-11-20 07:43:04 +08:00
commit 038e8cf776
24 changed files with 292 additions and 48 deletions

View file

@ -10,6 +10,7 @@ module.exports = LevelOptions =
hidesRealTimePlayback: true
requiredGear: {feet: 'simple-boots'}
restrictedGear: {feet: 'leather-boots'}
requiredCode: ['moveRight']
'gems-in-the-deep':
disableSpaces: true
hidesSubmitUntilRun: true
@ -71,8 +72,10 @@ module.exports = LevelOptions =
hidesRealTimePlayback: true
requiredGear: {feet: 'simple-boots', 'right-hand': 'simple-sword', waist: 'leather-belt'}
restrictedGear: {feet: 'leather-boots'}
requiredCode: ['Brak']
'favorable-odds':
disableSpaces: true
hidesPlayButton: true
hidesRunShortcut: true
hidesHUD: true
hidesSay: true
@ -82,6 +85,7 @@ module.exports = LevelOptions =
restrictedGear: {feet: 'leather-boots'}
'the-raised-sword':
disableSpaces: true
hidesPlayButton: true
hidesRunShortcut: true
hidesHUD: true
hidesSay: true
@ -97,6 +101,7 @@ module.exports = LevelOptions =
hidesRealTimePlayback: true
requiredGear: {feet: 'simple-boots', 'programming-book': 'programmaticon-i'}
restrictedGear: {feet: 'leather-boots'}
requiredCode: ['loop']
'haunted-kithmaze':
hidesRunShortcut: true
hidesHUD: true
@ -105,6 +110,7 @@ module.exports = LevelOptions =
hidesRealTimePlayback: true
requiredGear: {feet: 'simple-boots', 'programming-book': 'programmaticon-i'}
restrictedGear: {feet: 'leather-boots'}
requiredCode: ['loop']
'descending-further':
hidesHUD: true
hidesSay: true
@ -140,6 +146,8 @@ module.exports = LevelOptions =
hidesRealTimePlayback: true
requiredGear: {feet: 'simple-boots', 'right-hand': 'simple-sword', 'programming-book': 'programmaticon-i', eyes: 'crude-glasses', torso: 'leather-tunic'}
restrictedGear: {feet: 'leather-boots'}
requiredCode: ['findNearestEnemy']
suspectCode: [{name: 'lone-find-nearest-enemy', pattern: /^[ ]*(self|this|@)?[:.]?findNearestEnemy()/m}]
'lowly-kithmen':
hidesHUD: true
hidesSay: true
@ -147,6 +155,8 @@ module.exports = LevelOptions =
hidesRealTimePlayback: true
requiredGear: {feet: 'simple-boots', 'right-hand': 'simple-sword', 'programming-book': 'programmaticon-i', eyes: 'crude-glasses', torso: 'leather-tunic'}
restrictedGear: {feet: 'leather-boots'}
requiredCode: ['findNearestEnemy']
suspectCode: [{name: 'lone-find-nearest-enemy', pattern: /^[ ]*(self|this|@)?[:.]?findNearestEnemy()/m}]
'closing-the-distance':
hidesHUD: true
hidesSay: true
@ -154,6 +164,7 @@ module.exports = LevelOptions =
hidesRealTimePlayback: true
requiredGear: {feet: 'simple-boots', 'right-hand': 'simple-sword', torso: 'leather-tunic', eyes: 'crude-glasses'}
restrictedGear: {feet: 'leather-boots'}
suspectCode: [{name: 'lone-find-nearest-enemy', pattern: /^[ ]*(self|this|@)?[:.]?findNearestEnemy()/m}]
'tactical-strike':
hidesHUD: true
hidesSay: true
@ -161,12 +172,14 @@ module.exports = LevelOptions =
hidesRealTimePlayback: true
requiredGear: {feet: 'simple-boots', 'right-hand': 'simple-sword', torso: 'leather-tunic', eyes: 'crude-glasses'}
restrictedGear: {feet: 'leather-boots'}
suspectCode: [{name: 'lone-find-nearest-enemy', pattern: /^[ ]*(self|this|@)?[:.]?findNearestEnemy()/m}]
'the-final-kithmaze':
hidesHUD: true
hidesSay: true
hidesCodeToolbar: true
hidesRealTimePlayback: true
requiredGear: {feet: 'simple-boots', 'right-hand': 'simple-sword', torso: 'leather-tunic', 'programming-book': 'programmaticon-i', eyes: 'crude-glasses'}
suspectCode: [{name: 'lone-find-nearest-enemy', pattern: /^[ ]*(self|this|@)?[:.]?findNearestEnemy()/m}]
'the-gauntlet':
hidesHUD: true
hidesSay: true
@ -174,6 +187,7 @@ module.exports = LevelOptions =
hidesRealTimePlayback: true
requiredGear: {feet: 'simple-boots', 'right-hand': 'simple-sword', torso: 'leather-tunic', 'programming-book': 'programmaticon-i', eyes: 'crude-glasses'}
restrictedGear: {feet: 'leather-boots'}
suspectCode: [{name: 'lone-find-nearest-enemy', pattern: /^[ ]*(self|this|@)?[:.]?findNearestEnemy()/m}]
'kithgard-gates':
hidesSay: true
hidesCodeToolbar: true

View file

@ -6,6 +6,7 @@ module.exports = class CoordinateDisplay extends createjs.Container
'surface:mouse-over': 'onMouseOver'
'surface:stage-mouse-down': 'onMouseDown'
'camera:zoom-updated': 'onZoomUpdated'
'level:flag-color-selected': 'onFlagColorSelected'
constructor: (options) ->
super()
@ -60,6 +61,9 @@ module.exports = class CoordinateDisplay extends createjs.Container
@hide()
@show()
onFlagColorSelected: (e) ->
@placingFlag = Boolean e.color
hide: ->
return unless @label.parent
@removeChild @label
@ -154,6 +158,6 @@ module.exports = class CoordinateDisplay extends createjs.Container
@y = sup.y
@addChild @background
@addChild @label
@addChild @pointMarker
@addChild @pointMarker unless @placingFlag
@updateCache()
Backbone.Mediator.publish 'surface:coordinates-shown', {}

View file

@ -664,7 +664,9 @@ module.exports = Lank = class Lank extends CocoClass
updateLabels: ->
return unless @thang
blurb = if @thang.health <= 0 then null else @thang.sayMessage # Dead men tell no tales
@addLabel 'say', Label.STYLE_SAY if blurb
blurb = null if blurb in ['For Thoktar!', 'Bones!', 'Behead!', 'Destroy!', 'Die, humans!'] # Let's just hear, not see, these ones.
labelStyle = if /Hero Placeholder/.test(@thang.id) then Label.STYLE_DIALOGUE else Label.STYLE_SAY
@addLabel 'say', labelStyle if blurb
if @labels.say?.setText blurb
@notifySpeechUpdated blurb: blurb
label.update() for name, label of @labels

View file

@ -50,6 +50,8 @@ class CocoModel extends Backbone.Model
@loading = false
@jqxhr = null
@loadFromBackup()
getCreationDate: -> new Date(parseInt(@id.slice(0,8), 16)*1000)
getNormalizedURL: -> "#{@urlRoot}/#{@id}"

View file

@ -35,7 +35,7 @@ module.exports =
'tome:toggle-spell-list': c.object {title: 'Toggle Spell List', description: 'Published when you toggle the dropdown for a thang\'s spells'}
'tome:reload-code': c.object {title: 'Reload Code', description: 'Published when you reset a spell to its original source', required: ['spell']},
'tome:reload-code': c.object {title: 'Reload Code', description: 'Published when you reset a spell to its original source', required: []},
spell: {type: 'object'}
'tome:palette-cleared': c.object {title: 'Palette Cleared', description: 'Published when the spell palette is about to be cleared and recreated.'},
@ -122,6 +122,10 @@ module.exports =
'tome:required-code-fragment-deleted': c.object {title: 'Required Code Fragment Deleted', description: 'Published when a required code fragment is deleted from the sample code.', required: ['codeFragment']},
codeFragment: {type: 'string'}
'tome:suspect-code-fragment-added': c.object {title: 'Suspect Code Fragment Added', description: 'Published when a suspect code fragment is added to the sample code.', required: ['codeFragment']},
codeFragment: {type: 'string'}
codeLanguage: {type: 'string'}
'tome:winnability-updated': c.object {title: 'Winnability Updated', description: 'When we think we can now win (or can no longer win), we may want to emphasize the submit button versus the run button (or vice versa), so this fires when we get new goal states (even preloaded goal states) suggesting success or failure change.', required: ['winnable']},
winnable: {type: 'boolean'}

View file

@ -9,6 +9,7 @@ module.exports =
thang: {type: 'object'}
killer: {type: 'object'}
killerHealth: {type: ['number', 'undefined']}
maxHealth: {type: 'number'}
'world:thang-touched-goal': c.object {required: ['actor', 'touched']},
replacedNoteChain: {type: 'array'}

View file

@ -43,6 +43,13 @@ $level-resize-transition-time: 0.5s
visibility: hidden
#gold-view
right: 1%
@include box-shadow(-1px 1px 10px cyan)
.team-gold
font-size: 2vw
line-height: 2vw
img
width: 1.8vw
heighT: 1.8vw
#control-bar-view .title
left: 20%
width: 60%

View file

@ -12,11 +12,13 @@
padding: 19px 0px 2px 25px
z-index: 3
font-size: 14px
min-width: 230px
&.brighter
font-size: 18px
font-size: 1.4vw
border-width: 0.91vw 1.22vw 3.10vw 0.91vw
min-width: 23vw
.goals-status
margin: 5px 0 0 0

View file

@ -9,7 +9,7 @@
z-index: 6
@include transition(box-shadow .2s linear)
@include user-select(none)
padding: 4px
padding: 0.4vw
background: transparent url(/images/level/gold_background.png) no-repeat
background-size: 100% 100%
border-radius: 4px
@ -18,9 +18,9 @@
box-shadow: 2px 2px 2px black
.team-gold
font-size: 18px
font-size: 1.4vw
line-height: 1.4vw
margin: 0
line-height: 20px
color: hsla(205,0%,51%,1)
display: inline-block
padding: 0px 4px
@ -35,11 +35,12 @@
color: hsla(116,80%,51%,1)
img
width: 16px
height: 16px
width: 1.2vw
height: 1.2vw
border-radius: 2px
padding: 1px
margin-top: -1px
padding: 0.1vw
margin-top: -0.2vw
margin-right: 0.1vw
.gold-amount
display: inline-block

View file

@ -80,6 +80,7 @@
h1:not(.not-code), h2:not(.not-code), h3:not(.not-code), h4:not(.not-code), h5:not(.not-code), h6:not(.not-code)
font-family: Menlo, Monaco, Consolas, "Courier New", monospace
font-variant: normal
.popover-title
background-color: transparent

View file

@ -1,4 +1,82 @@
#play-achievements-modal
.achievement-view
color: black
.modal-header
padding-bottom: 20px
img.icon
float: left
width: 40px
margin-right: 10px
//- Unachieved Panels
.panel
margin: 5px 0
position: relative
border: 2px solid rgb(75,75,75)
padding: 2px
h3
margin: 0 0 0 50px
color: rgb(75,75,75)
p
margin: 0 0 0 50px
color: rgb(75,75,75)
.panel-body
padding: 5px 150px 5px 5px
border: 2px solid rgb(150,150,150)
.created
position: absolute
right: 10px
top: 5px
color: rgb(75,75,75)
font-size: 12px
//- Achieved Panels
.panel.earned
background: rgb(50,40,33)
border: 5px solid rgb(26,21,17)
padding: 0
h3
color: white
p
color: rgb(203,170,148)
.panel-body
border: 2px solid rgb(75,62,51)
.created
color: rgb(255,189,68)
//- Rewards
.rewards
position: absolute
right: .2em
//bottom: 10px
top: 29px
.label
font-size: 18px
margin-left: 5px
color: rgb(50,40,33)
background: rgb(203,170,148)
.gems
background: #94ccc7
.worth
background: #d8c488
img
width: 12px
height: 12px

View file

@ -3,7 +3,6 @@ h3.problem-alert-title(data-i18n="play_level.problem_alert_title") Fix Your Code
if hint
span.problem-title!= hint
br
br
span.problem-subtitle!= message
else
span.problem-title!= message

View file

@ -1,5 +1,5 @@
h4
span= doc.shortName
span.prop-name= doc.shortName
| -
code.prop-type= doc.type == 'function' && doc.owner == 'this' ? 'method' : doc.type
if doc.type != 'function'

View file

@ -4,4 +4,29 @@ block modal-header-content
h3(data-i18n="play.achievements") Achievements
block modal-body-content
p TODO: show all dem achievements
for achievement in achievements
.panel(class=achievement.earned ? 'earned' : '')
.panel-body
img.icon(src=achievement.getImageURL())
h3= achievement.name
p= achievement.description
if achievement.earnedDate
.created=moment(achievement.earnedDate).fromNow()
else
.created(data-i18n="user.status_unfinished")
.rewards
- rewards = achievement.get('rewards')
- rewards = { gems: 100 }
if rewards && rewards.gems
span.gems.label.label-default
span= rewards.gems
img.gem(src="/images/common/gem.png")
- worth = achievement.get('worth')
if worth
span.worth.label.label-default
span #{worth}xp
// maybe add more icons/numbers for items, heroes, levels, xp?
block modal-footer

View file

@ -43,10 +43,10 @@
.game-controls.header-font
button.btn.items(data-toggle='coco-modal', data-target='play/modal/PlayItemsModal', data-i18n="[title]play.items")
button.btn.heroes(data-toggle='coco-modal', data-target='play/modal/PlayHeroesModal', data-i18n="[title]play.heroes")
button.btn.achievements(data-toggle='coco-modal', data-target='play/modal/PlayAchievementsModal', data-i18n="[title]play.achievements")
if me.get('anonymous') === false
button.btn.gems(data-toggle='coco-modal', data-target='play/modal/BuyGemsModal', data-i18n="[title]play.buy_gems")
if me.isAdmin()
button.btn.achievements(data-toggle='coco-modal', data-target='play/modal/PlayAchievementsModal', data-i18n="[title]play.achievements")
button.btn.account(data-toggle='coco-modal', data-target='play/modal/PlayAccountModal', data-i18n="[title]play.account")
button.btn.settings(data-toggle='coco-modal', data-target='play/modal/PlaySettingsModal', data-i18n="[title]play.settings")
else if me.get('anonymous', true)

View file

@ -86,7 +86,7 @@ module.exports = class InventoryModal extends ModalView
locked = not (item.get('original') in me.items())
locked = false if me.get('slug') is 'nick'
if not item.getFrontFacingStats().props.length and not _.size item.getFrontFacingStats().stats # Temp: while there are placeholder items
if not item.getFrontFacingStats().props.length and not _.size(item.getFrontFacingStats().stats) and not locked # Temp: while there are placeholder items
null # Don't put into a collection
else if locked and item.get('slug') isnt 'simple-boots'
@itemGroups.lockedItems.add(item)

View file

@ -102,7 +102,7 @@ module.exports = class WorldMapView extends RootView
context.isIPadApp = application.isIPadApp
context.mapType = _.string.slugify @terrain
context.nextLevel = @nextLevel
context.forestIsAvailable = '541b67f71ccc8eaae19f3c62' in (me.get('earned')?.levels or [])
context.forestIsAvailable = @startedForestLevel or '541b67f71ccc8eaae19f3c62' in (me.get('earned')?.levels or [])
context
afterRender: ->
@ -131,8 +131,10 @@ module.exports = class WorldMapView extends RootView
@openModalView authModal
onSessionsLoaded: (e) ->
forestLevels = (f.id for f in forest)
for session in @sessions.models
@levelStatusMap[session.get('levelID')] = if session.get('state')?.complete then 'complete' else 'started'
@startedForestLevel = true if session.get('levelID') in forestLevels
if @nextLevel and @levelStatusMap[@nextLevel] is 'complete'
@nextLevel = null
@render()
@ -771,3 +773,4 @@ if me.getKithmazeGroup() is 'the-first-kithmaze'
_.remove dungeon, id: 'haunted-kithmaze'
else
_.remove dungeon, id: 'the-first-kithmaze'
_.find(dungeon, id: 'the-raised-sword').nextLevels.continue = 'haunted-kithmaze'

View file

@ -6,4 +6,10 @@ module.exports = class ReloadLevelModal extends ModalView
template: template
events:
'click #restart-level-confirm-button': -> Backbone.Mediator.publish 'level:restart', {}
'click #restart-level-confirm-button': 'onClickRestart'
onClickRestart: (e) ->
if key.shift
Backbone.Mediator.publish 'level:restart', {}
else
Backbone.Mediator.publish 'tome:reload-code', {}

View file

@ -34,7 +34,7 @@ module.exports = class ProblemAlertView extends CocoView
getRenderData: (context={}) ->
context = super context
if @problem?
format = (s) -> s?.replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\n/g, '<br>')
format = (s) -> marked(s.replace(/</g, '&lt;').replace(/>/g, '&gt;')) if s?
context.message = format @problem.aetherProblem.message
context.hint = format @problem.aetherProblem.hint
context

View file

@ -394,7 +394,7 @@ module.exports = class SpellView extends CocoView
@focus() if cast
onCodeReload: (e) ->
return unless e.spell is @spell
return unless e.spell is @spell or not e.spell
@reloadCode true
@ace.clearSelection()
_.delay (=> @ace?.clearSelection()), 500 # Make double sure this gets done (saw some timing issues?)
@ -450,7 +450,8 @@ module.exports = class SpellView extends CocoView
_.throttle @updateLines, 500
_.throttle @hideProblemAlert, 500
]
onSignificantChange.push _.debounce @checkRequiredCode, 1500 if requiredCodePerLevel[@options.level.get('slug')]
onSignificantChange.push _.debounce @checkRequiredCode, 750 if LevelOptions[@options.level.get('slug')]?.requiredCode
onSignificantChange.push _.debounce @checkSuspectCode, 750 if LevelOptions[@options.level.get('slug')]?.suspectCode
@onCodeChangeMetaHandler = =>
return if @eventsSuppressed
Backbone.Mediator.publish 'audio-player:play-sound', trigger: 'code-change', volume: 0.5
@ -881,13 +882,26 @@ module.exports = class SpellView extends CocoView
checkRequiredCode: =>
return if @destroyed
source = @getSource().replace @singleLineCommentRegex(), ''
for requiredCodeFragment in requiredCodePerLevel[@options.level.get('slug')]
requiredCodeFragments = LevelOptions[@options.level.get('slug')].requiredCode
for requiredCodeFragment in requiredCodeFragments
# Could make this obey regular expressions like suspectCode if needed
if source.indexOf(requiredCodeFragment) is -1
@warnedCodeFragments ?= {}
unless @warnedCodeFragments[requiredCodeFragment]
Backbone.Mediator.publish 'tome:required-code-fragment-deleted', codeFragment: requiredCodeFragment
@warnedCodeFragments[requiredCodeFragment] = true
checkSuspectCode: =>
return if @destroyed
source = @getSource().replace @singleLineCommentRegex(), ''
suspectCodeFragments = LevelOptions[@options.level.get('slug')].suspectCode
for suspectCodeFragment in suspectCodeFragments
if suspectCodeFragment.pattern.test source
@warnedCodeFragments ?= {}
unless @warnedCodeFragments[suspectCodeFragment.name]
Backbone.Mediator.publish 'tome:suspect-code-fragment-added', codeFragment: suspectCodeFragment.name, codeLanguage: @spell.language
@warnedCodeFragments[suspectCodeFragment] = true
destroy: ->
$(@ace?.container).find('.ace_gutter').off 'click', '.ace_error, .ace_warning, .ace_info', @onAnnotationClick
$(@ace?.container).find('.ace_gutter').off 'click', @onGutterClick
@ -900,11 +914,3 @@ module.exports = class SpellView extends CocoView
@debugView?.destroy()
$(window).off 'resize', @onWindowResize
super()
requiredCodePerLevel =
'dungeons-of-kithgard': ['moveRight']
'true-names': ['Brak']
'the-first-kithmaze': ['loop']
'haunted-kithmaze': ['loop']
'lowly-kithmen': ['findNearestEnemy']

View file

@ -2,27 +2,92 @@ ModalView = require 'views/kinds/ModalView'
template = require 'templates/play/modal/play-achievements-modal'
CocoCollection = require 'collections/CocoCollection'
Achievement = require 'models/Achievement'
#AchievementView = require 'views/game-menu/AchievementView'
EarnedAchievement = require 'models/EarnedAchievement'
utils = require 'lib/utils'
PAGE_SIZE = 200
module.exports = class PlayAchievementsModal extends ModalView
className: 'modal fade play-modal'
template: template
modalWidthPercent: 90
id: 'play-achievements-modal'
#instant: true
#events:
# 'change input.select': 'onSelectionChanged'
plain: true
earnedMap: {}
constructor: (options) ->
super options
#@achievements = new CocoCollection([], {model: Achievement})
#@achievements.url = '/db/thang.type?view=achievements&project=name,description,components,original,rasterIcon'
#@supermodel.loadCollection(@achievements, 'achievements')
@achievements = new Backbone.Collection()
earnedMap = {}
achievementsFetcher = new CocoCollection([], {url: '/db/achievement', model: Achievement})
achievementsFetcher.setProjection([
'name'
'description'
'icon'
'worth'
'i18n'
'rewards'
'collection'
])
earnedAchievementsFetcher = new CocoCollection([], {url: '/db/earned_achievement', model: EarnedAchievement})
earnedAchievementsFetcher.setProjection([ 'achievement' ])
achievementsFetcher.skip = 0
achievementsFetcher.fetch({data: {skip: 0, limit: PAGE_SIZE}})
earnedAchievementsFetcher.skip = 0
earnedAchievementsFetcher.fetch({data: {skip: 0, limit: PAGE_SIZE}})
@listenTo achievementsFetcher, 'sync', @onAchievementsLoaded
@listenTo earnedAchievementsFetcher, 'sync', @onEarnedAchievementsLoaded
@supermodel.loadCollection(achievementsFetcher, 'achievement')
@supermodel.loadCollection(earnedAchievementsFetcher, 'achievement')
@onEverythingLoaded = _.after(2, @onEverythingLoaded)
onAchievementsLoaded: (fetcher) ->
needMore = fetcher.models.length is PAGE_SIZE
@achievements.add(fetcher.models)
if needMore
fetcher.skip += PAGE_SIZE
fetcher.fetch({data: {skip: fetcher.skip, limit: PAGE_SIZE}})
else
@stopListening(fetcher)
@onEverythingLoaded()
onEarnedAchievementsLoaded: (fetcher) ->
needMore = fetcher.models.length is PAGE_SIZE
for earned in fetcher.models
@earnedMap[earned.get('achievement')] = earned
if needMore
fetcher.skip += PAGE_SIZE
fetcher.fetch({data: {skip: fetcher.skip, limit: PAGE_SIZE}})
else
@stopListening(fetcher)
@onEverythingLoaded()
onEverythingLoaded: =>
@achievements.set(@achievements.filter((m) -> m.get('collection') isnt 'level.sessions'))
for achievement in @achievements.models
if earned = @earnedMap[achievement.id]
achievement.earned = earned
achievement.earnedDate = earned.getCreationDate()
achievement.earnedDate ?= ''
@achievements.comparator = (m) -> m.earnedDate
@achievements.sort()
@achievements.set(@achievements.models.reverse())
for achievement in @achievements.models
achievement.name = utils.i18n achievement.attributes, 'name'
achievement.description = utils.i18n achievement.attributes, 'description'
@render()
getRenderData: (context={}) ->
context = super(context)
#context.achievements = @achievements.models
context.achievements = @achievements.models
context
afterRender: ->

View file

@ -2,12 +2,6 @@ mongoose = require 'mongoose'
jsonschema = require '../../app/schemas/models/earned_achievement'
EarnedAchievementSchema = new mongoose.Schema({
created:
type: Date
default: Date.now
changed:
type: Date
default: Date.now
notified:
type: Boolean
default: false

View file

@ -16,7 +16,26 @@ class EarnedAchievementHandler extends Handler
get: (req, res) ->
return @getByAchievementIDs(req, res) if req.query.view is 'get-by-achievement-ids'
super(arguments...)
query = { user: req.user._id+''}
projection = {}
if req.query.project
projection[field] = 1 for field in req.query.project.split(',')
q = EarnedAchievement.find(query, projection)
skip = parseInt(req.query.skip)
if skip? and skip < 1000000
q.skip(skip)
limit = parseInt(req.query.limit)
if limit? and limit < 1000
q.limit(limit)
q.exec (err, documents) =>
return @sendDatabaseError(res, err) if err
documents = (@formatEntity(req, doc) for doc in documents)
@sendSuccess(res, documents)
getByAchievementIDs: (req, res) ->
query = { user: req.user._id+''}

View file

@ -129,6 +129,10 @@ module.exports = class Handler
term = req.query.term
matchedObjects = []
filters = if @modelClass.schema.uses_coco_versions or @modelClass.schema.uses_coco_permissions then [filter: {index: true}] else [filter: {}]
skip = parseInt(req.query.skip)
limit = parseInt(req.query.limit)
if @modelClass.schema.uses_coco_permissions and req.user
filters.push {filter: {index: req.user.get('id')}}
projection = null
@ -158,7 +162,14 @@ module.exports = class Handler
else
args = [filter.filter]
args.push projection if projection
@modelClass.find(args...).limit(FETCH_LIMIT).exec callback
q = @modelClass.find(args...)
if skip? and skip < 1000000
q.skip(skip)
if limit? and limit < FETCH_LIMIT
q.limit(limit)
else
q.limit(FETCH_LIMIT)
q.exec callback
# if it's not a text search but the user is an admin, let him try stuff anyway
else if req.user?.isAdmin()
# admins can send any sort of query down the wire