Add hero-practice level type and threshold to schema
Filtering out hero-practice levels from classrooms until the Ux supports them.
This commit is contained in:
parent
cd30e4d083
commit
e0170d0339
15 changed files with 46 additions and 26 deletions
app
models
schemas/models
views
server/middleware
spec/server/functional
|
@ -58,7 +58,7 @@ module.exports = class Level extends CocoModel
|
||||||
|
|
||||||
denormalize: (supermodel, session, otherSession) ->
|
denormalize: (supermodel, session, otherSession) ->
|
||||||
o = $.extend true, {}, @attributes
|
o = $.extend true, {}, @attributes
|
||||||
if o.thangs and @get('type', true) in ['hero', 'hero-ladder', 'hero-coop', 'course', 'course-ladder', 'game-dev']
|
if o.thangs and @get('type', true) in ['hero', 'hero-ladder', 'hero-coop', 'course', 'course-ladder', 'game-dev', 'hero-practice']
|
||||||
thangTypesWithComponents = (tt for tt in supermodel.getModels(ThangType) when tt.get('components')?)
|
thangTypesWithComponents = (tt for tt in supermodel.getModels(ThangType) when tt.get('components')?)
|
||||||
thangTypesByOriginal = _.indexBy thangTypesWithComponents, (tt) -> tt.get('original') # Optimization
|
thangTypesByOriginal = _.indexBy thangTypesWithComponents, (tt) -> tt.get('original') # Optimization
|
||||||
for levelThang in o.thangs
|
for levelThang in o.thangs
|
||||||
|
|
|
@ -61,7 +61,7 @@ _.extend CampaignSchema.properties, {
|
||||||
i18n: { type: 'object', format: 'hidden' }
|
i18n: { type: 'object', format: 'hidden' }
|
||||||
requiresSubscription: { type: 'boolean' }
|
requiresSubscription: { type: 'boolean' }
|
||||||
replayable: { type: 'boolean' }
|
replayable: { type: 'boolean' }
|
||||||
type: {'enum': ['ladder', 'ladder-tutorial', 'hero', 'hero-ladder', 'hero-coop', 'course', 'course-ladder', 'game-dev']}
|
type: {'enum': ['ladder', 'ladder-tutorial', 'hero', 'hero-ladder', 'hero-coop', 'course', 'course-ladder', 'game-dev', 'hero-practice']}
|
||||||
slug: { type: 'string', format: 'hidden' }
|
slug: { type: 'string', format: 'hidden' }
|
||||||
original: { type: 'string', format: 'hidden' }
|
original: { type: 'string', format: 'hidden' }
|
||||||
adventurer: { type: 'boolean' }
|
adventurer: { type: 'boolean' }
|
||||||
|
|
|
@ -313,7 +313,7 @@ _.extend LevelSchema.properties,
|
||||||
icon: {type: 'string', format: 'image-file', title: 'Icon'}
|
icon: {type: 'string', format: 'image-file', title: 'Icon'}
|
||||||
banner: {type: 'string', format: 'image-file', title: 'Banner'}
|
banner: {type: 'string', format: 'image-file', title: 'Banner'}
|
||||||
goals: c.array {title: 'Goals', description: 'An array of goals which are visible to the player and can trigger scripts.'}, GoalSchema
|
goals: c.array {title: 'Goals', description: 'An array of goals which are visible to the player and can trigger scripts.'}, GoalSchema
|
||||||
type: c.shortString(title: 'Type', description: 'What kind of level this is.', 'enum': ['campaign', 'ladder', 'ladder-tutorial', 'hero', 'hero-ladder', 'hero-coop', 'course', 'course-ladder', 'game-dev'])
|
type: c.shortString(title: 'Type', description: 'What kind of level this is.', 'enum': ['campaign', 'ladder', 'ladder-tutorial', 'hero', 'hero-ladder', 'hero-coop', 'course', 'course-ladder', 'game-dev', 'hero-practice'])
|
||||||
terrain: c.terrainString
|
terrain: c.terrainString
|
||||||
showsGuide: c.shortString(title: 'Shows Guide', description: 'If the guide is shown at the beginning of the level.', 'enum': ['first-time', 'always'])
|
showsGuide: c.shortString(title: 'Shows Guide', description: 'If the guide is shown at the beginning of the level.', 'enum': ['first-time', 'always'])
|
||||||
requiresSubscription: {title: 'Requires Subscription', description: 'Whether this level is available to subscribers only.', type: 'boolean'}
|
requiresSubscription: {title: 'Requires Subscription', description: 'Whether this level is available to subscribers only.', type: 'boolean'}
|
||||||
|
@ -324,6 +324,7 @@ _.extend LevelSchema.properties,
|
||||||
url: c.url {title: 'URL', description: 'Link to the video on Vimeo.'}
|
url: c.url {title: 'URL', description: 'Link to the video on Vimeo.'}
|
||||||
replayable: {type: 'boolean', title: 'Replayable', description: 'Whether this (hero) level infinitely scales up its difficulty and can be beaten over and over for greater rewards.'}
|
replayable: {type: 'boolean', title: 'Replayable', description: 'Whether this (hero) level infinitely scales up its difficulty and can be beaten over and over for greater rewards.'}
|
||||||
buildTime: {type: 'number', description: 'How long it has taken to build this level.'}
|
buildTime: {type: 'number', description: 'How long it has taken to build this level.'}
|
||||||
|
practiceThresholdMinutes: {type: 'number', description: 'Players with larger playtimes may be directed to a practice level.'}
|
||||||
|
|
||||||
# Admin flags
|
# Admin flags
|
||||||
adventurer: { type: 'boolean' }
|
adventurer: { type: 'boolean' }
|
||||||
|
|
|
@ -46,7 +46,7 @@ module.exports = class ThangComponentConfigView extends CocoView
|
||||||
schema.default ?= {}
|
schema.default ?= {}
|
||||||
_.merge schema.default, @additionalDefaults if @additionalDefaults
|
_.merge schema.default, @additionalDefaults if @additionalDefaults
|
||||||
|
|
||||||
if @level?.get('type', true) in ['hero', 'hero-ladder', 'hero-coop', 'course', 'course-ladder', 'game-dev']
|
if @level?.get('type', true) in ['hero', 'hero-ladder', 'hero-coop', 'course', 'course-ladder', 'game-dev', 'hero-practice']
|
||||||
schema.required = []
|
schema.required = []
|
||||||
treemaOptions =
|
treemaOptions =
|
||||||
supermodel: @supermodel
|
supermodel: @supermodel
|
||||||
|
|
|
@ -41,7 +41,7 @@ module.exports = class LevelThangEditView extends CocoView
|
||||||
level: @level
|
level: @level
|
||||||
world: @world
|
world: @world
|
||||||
|
|
||||||
if @level.get('type', true) in ['hero', 'hero-ladder', 'hero-coop', 'course', 'course-ladder', 'game-dev'] then options.thangType = thangType
|
if @level.get('type', true) in ['hero', 'hero-ladder', 'hero-coop', 'course', 'course-ladder', 'game-dev', 'hero-practice'] then options.thangType = thangType
|
||||||
|
|
||||||
@thangComponentEditView = new ThangComponentsEditView options
|
@thangComponentEditView = new ThangComponentsEditView options
|
||||||
@listenTo @thangComponentEditView, 'components-changed', @onComponentsChanged
|
@listenTo @thangComponentEditView, 'components-changed', @onComponentsChanged
|
||||||
|
|
|
@ -585,14 +585,14 @@ module.exports = class ThangsTabView extends CocoView
|
||||||
if batchInsert
|
if batchInsert
|
||||||
if thangType.get('name') is 'Hero Placeholder'
|
if thangType.get('name') is 'Hero Placeholder'
|
||||||
thangID = 'Hero Placeholder'
|
thangID = 'Hero Placeholder'
|
||||||
return if not (@level.get('type', true) in ['hero', 'hero-ladder', 'hero-coop', 'course', 'course-ladder', 'game-dev']) or @getThangByID(thangID)
|
return if not (@level.get('type', true) in ['hero', 'hero-ladder', 'hero-coop', 'course', 'course-ladder', 'game-dev', 'hero-practice']) or @getThangByID(thangID)
|
||||||
else
|
else
|
||||||
thangID = "Random #{thangType.get('name')} #{@thangsBatch.length}"
|
thangID = "Random #{thangType.get('name')} #{@thangsBatch.length}"
|
||||||
else
|
else
|
||||||
thangID = Thang.nextID(thangType.get('name'), @world) until thangID and not @getThangByID(thangID)
|
thangID = Thang.nextID(thangType.get('name'), @world) until thangID and not @getThangByID(thangID)
|
||||||
if @cloneSourceThang
|
if @cloneSourceThang
|
||||||
components = _.cloneDeep @getThangByID(@cloneSourceThang.id).components
|
components = _.cloneDeep @getThangByID(@cloneSourceThang.id).components
|
||||||
else if @level.get('type', true) in ['hero', 'hero-ladder', 'hero-coop', 'course', 'course-ladder', 'game-dev']
|
else if @level.get('type', true) in ['hero', 'hero-ladder', 'hero-coop', 'course', 'course-ladder', 'game-dev', 'hero-practice']
|
||||||
components = [] # Load them all from default ThangType Components
|
components = [] # Load them all from default ThangType Components
|
||||||
else
|
else
|
||||||
components = _.cloneDeep thangType.get('components') ? []
|
components = _.cloneDeep thangType.get('components') ? []
|
||||||
|
|
|
@ -205,7 +205,7 @@ module.exports = class PlayLevelView extends RootView
|
||||||
@session = @levelLoader.session
|
@session = @levelLoader.session
|
||||||
@world = @levelLoader.world
|
@world = @levelLoader.world
|
||||||
@level = @levelLoader.level
|
@level = @levelLoader.level
|
||||||
@$el.addClass 'hero' if @level.get('type', true) in ['hero', 'hero-ladder', 'hero-coop', 'course', 'course-ladder', 'game-dev']
|
@$el.addClass 'hero' if @level.get('type', true) in ['hero', 'hero-ladder', 'hero-coop', 'course', 'course-ladder', 'game-dev', 'hero-practice']
|
||||||
@$el.addClass 'flags' if _.any(@world.thangs, (t) -> (t.programmableProperties and 'findFlags' in t.programmableProperties) or t.inventory?.flag) or @level.get('slug') is 'sky-span'
|
@$el.addClass 'flags' if _.any(@world.thangs, (t) -> (t.programmableProperties and 'findFlags' in t.programmableProperties) or t.inventory?.flag) or @level.get('slug') is 'sky-span'
|
||||||
# TODO: Update terminology to always be opponentSession or otherSession
|
# TODO: Update terminology to always be opponentSession or otherSession
|
||||||
# TODO: E.g. if it's always opponent right now, then variable names should be opponentSession until we have coop play
|
# TODO: E.g. if it's always opponent right now, then variable names should be opponentSession until we have coop play
|
||||||
|
@ -467,7 +467,7 @@ module.exports = class PlayLevelView extends RootView
|
||||||
return false if $.browser?.msie or $.browser?.msedge
|
return false if $.browser?.msie or $.browser?.msedge
|
||||||
return false if $.browser.linux
|
return false if $.browser.linux
|
||||||
return false if me.level() < 8
|
return false if me.level() < 8
|
||||||
if levelType in ['course', 'game-dev']
|
if levelType in ['course', 'game-dev', 'hero-practice']
|
||||||
return false
|
return false
|
||||||
else if levelType is 'hero' and gamesSimulated
|
else if levelType is 'hero' and gamesSimulated
|
||||||
return false if stillBuggy
|
return false if stillBuggy
|
||||||
|
@ -540,7 +540,7 @@ module.exports = class PlayLevelView extends RootView
|
||||||
onDonePressed: -> @showVictory()
|
onDonePressed: -> @showVictory()
|
||||||
|
|
||||||
onShowVictory: (e) ->
|
onShowVictory: (e) ->
|
||||||
$('#level-done-button').show() unless @level.get('type', true) in ['hero', 'hero-ladder', 'hero-coop', 'course', 'course-ladder', 'game-dev']
|
$('#level-done-button').show() unless @level.get('type', true) in ['hero', 'hero-ladder', 'hero-coop', 'course', 'course-ladder', 'game-dev', 'hero-practice']
|
||||||
@showVictory() if e.showModal
|
@showVictory() if e.showModal
|
||||||
return if @victorySeen
|
return if @victorySeen
|
||||||
@victorySeen = true
|
@victorySeen = true
|
||||||
|
@ -558,7 +558,7 @@ module.exports = class PlayLevelView extends RootView
|
||||||
return if @level.hasLocalChanges() # Don't award achievements when beating level changed in level editor
|
return if @level.hasLocalChanges() # Don't award achievements when beating level changed in level editor
|
||||||
@endHighlight()
|
@endHighlight()
|
||||||
options = {level: @level, supermodel: @supermodel, session: @session, hasReceivedMemoryWarning: @hasReceivedMemoryWarning, courseID: @courseID, courseInstanceID: @courseInstanceID, world: @world}
|
options = {level: @level, supermodel: @supermodel, session: @session, hasReceivedMemoryWarning: @hasReceivedMemoryWarning, courseID: @courseID, courseInstanceID: @courseInstanceID, world: @world}
|
||||||
ModalClass = if @level.get('type', true) in ['hero', 'hero-ladder', 'hero-coop', 'course', 'course-ladder', 'game-dev'] then HeroVictoryModal else VictoryModal
|
ModalClass = if @level.get('type', true) in ['hero', 'hero-ladder', 'hero-coop', 'course', 'course-ladder', 'game-dev', 'hero-practice'] then HeroVictoryModal else VictoryModal
|
||||||
ModalClass = CourseVictoryModal if @isCourseMode() or me.isSessionless()
|
ModalClass = CourseVictoryModal if @isCourseMode() or me.isSessionless()
|
||||||
ModalClass = PicoCTFVictoryModal if window.serverConfig.picoCTF
|
ModalClass = PicoCTFVictoryModal if window.serverConfig.picoCTF
|
||||||
victoryModal = new ModalClass(options)
|
victoryModal = new ModalClass(options)
|
||||||
|
|
|
@ -49,7 +49,7 @@ module.exports = class HeroVictoryModal extends ModalView
|
||||||
@session = options.session
|
@session = options.session
|
||||||
@level = options.level
|
@level = options.level
|
||||||
@thangTypes = {}
|
@thangTypes = {}
|
||||||
if @level.get('type', true) in ['hero', 'hero-ladder', 'course', 'course-ladder', 'game-dev']
|
if @level.get('type', true) in ['hero', 'hero-ladder', 'course', 'course-ladder', 'game-dev', 'hero-practice']
|
||||||
achievements = new CocoCollection([], {
|
achievements = new CocoCollection([], {
|
||||||
url: "/db/achievement?related=#{@session.get('level').original}"
|
url: "/db/achievement?related=#{@session.get('level').original}"
|
||||||
model: Achievement
|
model: Achievement
|
||||||
|
@ -155,7 +155,7 @@ module.exports = class HeroVictoryModal extends ModalView
|
||||||
c = super()
|
c = super()
|
||||||
c.levelName = utils.i18n @level.attributes, 'name'
|
c.levelName = utils.i18n @level.attributes, 'name'
|
||||||
# TODO: support 'game-dev'
|
# TODO: support 'game-dev'
|
||||||
if @level.get('type', true) not in ['hero', 'game-dev']
|
if @level.get('type', true) not in ['hero', 'game-dev', 'hero-practice']
|
||||||
c.victoryText = utils.i18n @level.get('victory') ? {}, 'body'
|
c.victoryText = utils.i18n @level.get('victory') ? {}, 'body'
|
||||||
earnedAchievementMap = _.indexBy(@newEarnedAchievements or [], (ea) -> ea.get('achievement'))
|
earnedAchievementMap = _.indexBy(@newEarnedAchievements or [], (ea) -> ea.get('achievement'))
|
||||||
for achievement in (@achievements?.models or [])
|
for achievement in (@achievements?.models or [])
|
||||||
|
@ -223,7 +223,7 @@ module.exports = class HeroVictoryModal extends ModalView
|
||||||
|
|
||||||
afterRender: ->
|
afterRender: ->
|
||||||
super()
|
super()
|
||||||
@$el.toggleClass 'with-achievements', @level.get('type', true) in ['hero', 'hero-ladder', 'game-dev'] # TODO: support game-dev
|
@$el.toggleClass 'with-achievements', @level.get('type', true) in ['hero', 'hero-ladder', 'game-dev', 'hero-practice'] # TODO: support game-dev
|
||||||
return unless @supermodel.finished()
|
return unless @supermodel.finished()
|
||||||
@playSelectionSound hero, true for original, hero of @thangTypes # Preload them
|
@playSelectionSound hero, true for original, hero of @thangTypes # Preload them
|
||||||
@updateSavingProgressStatus()
|
@updateSavingProgressStatus()
|
||||||
|
@ -233,7 +233,7 @@ module.exports = class HeroVictoryModal extends ModalView
|
||||||
@insertSubView @ladderSubmissionView, @$el.find('.ladder-submission-view')
|
@insertSubView @ladderSubmissionView, @$el.find('.ladder-submission-view')
|
||||||
|
|
||||||
initializeAnimations: ->
|
initializeAnimations: ->
|
||||||
return @endSequentialAnimations() unless @level.get('type', true) in ['hero', 'hero-ladder', 'game-dev'] # TODO: support game-dev
|
return @endSequentialAnimations() unless @level.get('type', true) in ['hero', 'hero-ladder', 'game-dev', 'hero-practice'] # TODO: support game-dev
|
||||||
@updateXPBars 0
|
@updateXPBars 0
|
||||||
#playVictorySound = => @playSound 'victory-title-appear' # TODO: actually add this
|
#playVictorySound = => @playSound 'victory-title-appear' # TODO: actually add this
|
||||||
@$el.find('#victory-header').delay(250).queue(->
|
@$el.find('#victory-header').delay(250).queue(->
|
||||||
|
@ -264,7 +264,7 @@ module.exports = class HeroVictoryModal extends ModalView
|
||||||
|
|
||||||
beginSequentialAnimations: ->
|
beginSequentialAnimations: ->
|
||||||
return if @destroyed
|
return if @destroyed
|
||||||
return unless @level.get('type', true) in ['hero', 'hero-ladder', 'game-dev'] # TODO: support game-dev
|
return unless @level.get('type', true) in ['hero', 'hero-ladder', 'game-dev', 'hero-practice'] # TODO: support game-dev
|
||||||
@sequentialAnimatedPanels = _.map(@animatedPanels.find('.reward-panel'), (panel) -> {
|
@sequentialAnimatedPanels = _.map(@animatedPanels.find('.reward-panel'), (panel) -> {
|
||||||
number: $(panel).data('number')
|
number: $(panel).data('number')
|
||||||
previousNumber: $(panel).data('previous-number')
|
previousNumber: $(panel).data('previous-number')
|
||||||
|
|
|
@ -171,7 +171,7 @@ module.exports = class Spell
|
||||||
writable = @permissions.readwrite.length > 0 and not @isAISource
|
writable = @permissions.readwrite.length > 0 and not @isAISource
|
||||||
skipProtectAPI = @skipProtectAPI or not writable or @levelType in ['game-dev']
|
skipProtectAPI = @skipProtectAPI or not writable or @levelType in ['game-dev']
|
||||||
problemContext = @createProblemContext thang
|
problemContext = @createProblemContext thang
|
||||||
includeFlow = (@levelType in ['hero', 'hero-ladder', 'hero-coop', 'course', 'course-ladder', 'game-dev']) and not skipProtectAPI
|
includeFlow = (@levelType in ['hero', 'hero-ladder', 'hero-coop', 'course', 'course-ladder', 'game-dev', 'hero-practice']) and not skipProtectAPI
|
||||||
aetherOptions = createAetherOptions
|
aetherOptions = createAetherOptions
|
||||||
functionName: @name
|
functionName: @name
|
||||||
codeLanguage: @language
|
codeLanguage: @language
|
||||||
|
|
|
@ -84,7 +84,7 @@ module.exports = class SpellPaletteEntryView extends CocoView
|
||||||
Backbone.Mediator.publish 'tome:palette-pin-toggled', entry: @, pinned: @popoverPinned
|
Backbone.Mediator.publish 'tome:palette-pin-toggled', entry: @, pinned: @popoverPinned
|
||||||
|
|
||||||
onClick: (e) =>
|
onClick: (e) =>
|
||||||
if true or @options.level.get('type', true) in ['hero', 'hero-ladder', 'hero-coop', 'course', 'course-ladder', 'game-dev']
|
if true or @options.level.get('type', true) in ['hero', 'hero-ladder', 'hero-coop', 'course', 'course-ladder', 'game-dev', 'hero-practice']
|
||||||
# Jiggle instead of pin for hero levels
|
# Jiggle instead of pin for hero levels
|
||||||
# Actually, do it all the time, because we recently busted the pin CSS. TODO: restore pinning
|
# Actually, do it all the time, because we recently busted the pin CSS. TODO: restore pinning
|
||||||
jigglyPopover = $('.spell-palette-popover.popover')
|
jigglyPopover = $('.spell-palette-popover.popover')
|
||||||
|
|
|
@ -157,7 +157,7 @@ module.exports = class SpellPaletteView extends CocoView
|
||||||
else
|
else
|
||||||
propStorage =
|
propStorage =
|
||||||
'this': ['apiProperties', 'apiMethods']
|
'this': ['apiProperties', 'apiMethods']
|
||||||
if not (@options.level.get('type', true) in ['hero', 'hero-ladder', 'hero-coop', 'course', 'course-ladder', 'game-dev']) or not @options.programmable
|
if not (@options.level.get('type', true) in ['hero', 'hero-ladder', 'hero-coop', 'course', 'course-ladder', 'game-dev', 'hero-practice']) or not @options.programmable
|
||||||
@organizePalette propStorage, allDocs, excludedDocs
|
@organizePalette propStorage, allDocs, excludedDocs
|
||||||
else
|
else
|
||||||
@organizePaletteHero propStorage, allDocs, excludedDocs
|
@organizePaletteHero propStorage, allDocs, excludedDocs
|
||||||
|
@ -199,7 +199,7 @@ module.exports = class SpellPaletteView extends CocoView
|
||||||
if tabbify and _.find @entries, ((entry) -> entry.doc.owner isnt 'this')
|
if tabbify and _.find @entries, ((entry) -> entry.doc.owner isnt 'this')
|
||||||
@entryGroups = _.groupBy @entries, groupForEntry
|
@entryGroups = _.groupBy @entries, groupForEntry
|
||||||
else
|
else
|
||||||
i18nKey = if @options.level.get('type', true) in ['hero', 'hero-ladder', 'hero-coop', 'course', 'course-ladder', 'game-dev'] then 'play_level.tome_your_skills' else 'play_level.tome_available_spells'
|
i18nKey = if @options.level.get('type', true) in ['hero', 'hero-ladder', 'hero-coop', 'course', 'course-ladder', 'game-dev', 'hero-practice'] then 'play_level.tome_your_skills' else 'play_level.tome_available_spells'
|
||||||
defaultGroup = $.i18n.t i18nKey
|
defaultGroup = $.i18n.t i18nKey
|
||||||
@entryGroups = {}
|
@entryGroups = {}
|
||||||
@entryGroups[defaultGroup] = @entries
|
@entryGroups[defaultGroup] = @entries
|
||||||
|
|
|
@ -635,7 +635,7 @@ module.exports = class SpellView extends CocoView
|
||||||
@createToolbarView()
|
@createToolbarView()
|
||||||
|
|
||||||
createDebugView: ->
|
createDebugView: ->
|
||||||
return if @options.level.get('type', true) in ['hero', 'hero-ladder', 'hero-coop', 'course', 'course-ladder', 'game-dev'] # We'll turn this on later, maybe, but not yet.
|
return if @options.level.get('type', true) in ['hero', 'hero-ladder', 'hero-coop', 'course', 'course-ladder', 'game-dev', 'hero-practice'] # We'll turn this on later, maybe, but not yet.
|
||||||
@debugView = new SpellDebugView ace: @ace, thang: @thang, spell:@spell
|
@debugView = new SpellDebugView ace: @ace, thang: @thang, spell:@spell
|
||||||
@$el.append @debugView.render().$el.hide()
|
@$el.append @debugView.render().$el.hide()
|
||||||
|
|
||||||
|
|
|
@ -60,7 +60,7 @@ module.exports = class TomeView extends CocoView
|
||||||
@worker = @createWorker()
|
@worker = @createWorker()
|
||||||
programmableThangs = _.filter @options.thangs, (t) -> t.isProgrammable and t.programmableMethods
|
programmableThangs = _.filter @options.thangs, (t) -> t.isProgrammable and t.programmableMethods
|
||||||
@createSpells programmableThangs, programmableThangs[0]?.world # Do before spellList, thangList, and castButton
|
@createSpells programmableThangs, programmableThangs[0]?.world # Do before spellList, thangList, and castButton
|
||||||
unless @options.level.get('type', true) in ['hero', 'hero-ladder', 'hero-coop', 'course', 'course-ladder', 'game-dev']
|
unless @options.level.get('type', true) in ['hero', 'hero-ladder', 'hero-coop', 'course', 'course-ladder', 'game-dev', 'hero-practice']
|
||||||
@spellList = @insertSubView new SpellListView spells: @spells, supermodel: @supermodel, level: @options.level
|
@spellList = @insertSubView new SpellListView spells: @spells, supermodel: @supermodel, level: @options.level
|
||||||
@castButton = @insertSubView new CastButtonView spells: @spells, level: @options.level, session: @options.session, god: @options.god
|
@castButton = @insertSubView new CastButtonView spells: @spells, level: @options.level, session: @options.session, god: @options.god
|
||||||
@teamSpellMap = @generateTeamSpellMap(@spells)
|
@teamSpellMap = @generateTeamSpellMap(@spells)
|
||||||
|
@ -194,7 +194,7 @@ module.exports = class TomeView extends CocoView
|
||||||
@castButton?.$el.hide()
|
@castButton?.$el.hide()
|
||||||
|
|
||||||
onSpriteSelected: (e) ->
|
onSpriteSelected: (e) ->
|
||||||
return if @spellView and @options.level.get('type', true) in ['hero', 'hero-ladder', 'hero-coop', 'course', 'course-ladder', 'game-dev'] # Never deselect the hero in the Tome.
|
return if @spellView and @options.level.get('type', true) in ['hero', 'hero-ladder', 'hero-coop', 'course', 'course-ladder', 'game-dev', 'hero-practice'] # Never deselect the hero in the Tome.
|
||||||
thang = e.thang
|
thang = e.thang
|
||||||
spellName = e.spellName
|
spellName = e.spellName
|
||||||
@spellList?.$el.hide()
|
@spellList?.$el.hide()
|
||||||
|
|
|
@ -141,7 +141,7 @@ module.exports =
|
||||||
classroom.set 'members', []
|
classroom.set 'members', []
|
||||||
database.assignBody(req, classroom)
|
database.assignBody(req, classroom)
|
||||||
|
|
||||||
# copy over data from how courses are right now
|
# Copy over data from how courses are right now
|
||||||
courses = yield Course.find()
|
courses = yield Course.find()
|
||||||
campaigns = yield Campaign.find({_id: {$in: (course.get('campaignID') for course in courses)}})
|
campaigns = yield Campaign.find({_id: {$in: (course.get('campaignID') for course in courses)}})
|
||||||
campaignMap = {}
|
campaignMap = {}
|
||||||
|
@ -151,6 +151,8 @@ module.exports =
|
||||||
courseData = { _id: course._id, levels: [] }
|
courseData = { _id: course._id, levels: [] }
|
||||||
campaign = campaignMap[course.get('campaignID').toString()]
|
campaign = campaignMap[course.get('campaignID').toString()]
|
||||||
levels = _.values(campaign.get('levels'))
|
levels = _.values(campaign.get('levels'))
|
||||||
|
# TODO: remove hero-practice filter after classroom Ux supports practice levels
|
||||||
|
levels = _.reject(levels, {'type': 'hero-practice'})
|
||||||
levels = _.sortBy(levels, 'campaignIndex')
|
levels = _.sortBy(levels, 'campaignIndex')
|
||||||
for level in levels
|
for level in levels
|
||||||
levelData = { original: mongoose.Types.ObjectId(level.original) }
|
levelData = { original: mongoose.Types.ObjectId(level.original) }
|
||||||
|
|
|
@ -86,7 +86,14 @@ describe 'POST /db/classroom', ->
|
||||||
[res, body] = yield request.postAsync({uri: getURL('/db/level'), json: levelJSONB})
|
[res, body] = yield request.postAsync({uri: getURL('/db/level'), json: levelJSONB})
|
||||||
expect(res.statusCode).toBe(200)
|
expect(res.statusCode).toBe(200)
|
||||||
@levelB = yield Level.findById(res.body._id)
|
@levelB = yield Level.findById(res.body._id)
|
||||||
|
levelJSONC = { name: 'Level C', permissions: [{access: 'owner', target: admin.id}], type: 'hero-practice' }
|
||||||
|
[res, body] = yield request.postAsync({uri: getURL('/db/level'), json: levelJSONC})
|
||||||
|
expect(res.statusCode).toBe(200)
|
||||||
|
@levelC = yield Level.findById(res.body._id)
|
||||||
campaignJSON = { name: 'Campaign', levels: {} }
|
campaignJSON = { name: 'Campaign', levels: {} }
|
||||||
|
paredLevelC = _.pick(@levelC.toObject(), 'name', 'original', 'type', 'slug')
|
||||||
|
paredLevelC.campaignIndex = 2
|
||||||
|
campaignJSON.levels[@levelC.get('original').toString()] = paredLevelC
|
||||||
paredLevelB = _.pick(@levelB.toObject(), 'name', 'original', 'type', 'slug')
|
paredLevelB = _.pick(@levelB.toObject(), 'name', 'original', 'type', 'slug')
|
||||||
paredLevelB.campaignIndex = 1
|
paredLevelB.campaignIndex = 1
|
||||||
campaignJSON.levels[@levelB.get('original').toString()] = paredLevelB
|
campaignJSON.levels[@levelB.get('original').toString()] = paredLevelB
|
||||||
|
@ -124,7 +131,7 @@ describe 'POST /db/classroom', ->
|
||||||
[res, body] = yield request.postAsync {uri: classroomsURL, json: data }
|
[res, body] = yield request.postAsync {uri: classroomsURL, json: data }
|
||||||
expect(res.statusCode).toBe(403)
|
expect(res.statusCode).toBe(403)
|
||||||
done()
|
done()
|
||||||
|
|
||||||
it 'makes a copy of the list of all levels in all courses', utils.wrap (done) ->
|
it 'makes a copy of the list of all levels in all courses', utils.wrap (done) ->
|
||||||
teacher = yield utils.initUser({role: 'teacher'})
|
teacher = yield utils.initUser({role: 'teacher'})
|
||||||
yield utils.loginUser(teacher)
|
yield utils.loginUser(teacher)
|
||||||
|
@ -136,7 +143,17 @@ describe 'POST /db/classroom', ->
|
||||||
expect(classroom.get('courses')[0].levels[0].slug).toBe('level-a')
|
expect(classroom.get('courses')[0].levels[0].slug).toBe('level-a')
|
||||||
expect(classroom.get('courses')[0].levels[0].name).toBe('Level A')
|
expect(classroom.get('courses')[0].levels[0].name).toBe('Level A')
|
||||||
done()
|
done()
|
||||||
|
|
||||||
|
it 'makes a copy of the list of all non-practice levels in all courses', utils.wrap (done) ->
|
||||||
|
teacher = yield utils.initUser({role: 'teacher'})
|
||||||
|
yield utils.loginUser(teacher)
|
||||||
|
data = { name: 'tmp Classroom 2' }
|
||||||
|
[res, body] = yield request.postAsync {uri: classroomsURL, json: data }
|
||||||
|
classroom = yield Classroom.findById(res.body._id)
|
||||||
|
# console.log(JSON.stringify(classroom.get('courses')[0], null, 2));
|
||||||
|
expect(classroom.get('courses')[0].levels.length).toEqual(2)
|
||||||
|
done()
|
||||||
|
|
||||||
describe 'GET /db/classroom/:handle/levels', ->
|
describe 'GET /db/classroom/:handle/levels', ->
|
||||||
|
|
||||||
beforeEach utils.wrap (done) ->
|
beforeEach utils.wrap (done) ->
|
||||||
|
|
Reference in a new issue