mirror of
https://github.com/codeninjasllc/codecombat.git
synced 2024-11-23 15:48:11 -05:00
Include ladder levels in level stats in teacher views, clean client test logs
This commit is contained in:
parent
490ea8d1bc
commit
514fce349a
8 changed files with 43 additions and 44 deletions
|
@ -12,6 +12,8 @@ app = require 'core/application'
|
|||
World = require 'lib/world/world'
|
||||
utils = require 'core/utils'
|
||||
|
||||
LOG = false
|
||||
|
||||
# This is an initial stab at unifying loading and setup into a single place which can
|
||||
# monitor everything and keep a LoadingScreen visible overall progress.
|
||||
#
|
||||
|
@ -147,7 +149,7 @@ module.exports = class LevelLoader extends CocoClass
|
|||
@listenToOnce @opponentSession, 'sync', @loadDependenciesForSession
|
||||
|
||||
loadDependenciesForSession: (session) ->
|
||||
console.log "Loading dependencies for session: ", session
|
||||
console.log "Loading dependencies for session: ", session if LOG
|
||||
if me.id isnt session.get 'creator'
|
||||
session.patch = session.save = -> console.error "Not saving session, since we didn't create it."
|
||||
else if codeLanguage = utils.getQueryVariable 'codeLanguage'
|
||||
|
@ -172,11 +174,11 @@ module.exports = class LevelLoader extends CocoClass
|
|||
@consolidateFlagHistory() if @session.loaded
|
||||
if @level.get('type', true) in ['course'] # course-ladder is hard to handle because there's 2 sessions
|
||||
heroConfig = me.get('heroConfig')
|
||||
console.log "Course mode, loading custom hero: ", heroConfig
|
||||
console.log "Course mode, loading custom hero: ", heroConfig if LOG
|
||||
return if not heroConfig
|
||||
url = "/db/thang.type/#{heroConfig.thangType}/version"
|
||||
if heroResource = @maybeLoadURL(url, ThangType, 'thang')
|
||||
console.log "Pushing resource: ", heroResource
|
||||
console.log "Pushing resource: ", heroResource if LOG
|
||||
@worldNecessities.push heroResource
|
||||
@sessionDependenciesRegistered[session.id] = true
|
||||
return
|
||||
|
@ -345,7 +347,7 @@ module.exports = class LevelLoader extends CocoClass
|
|||
true
|
||||
|
||||
onWorldNecessitiesLoaded: ->
|
||||
console.log "World necessities loaded."
|
||||
console.log "World necessities loaded." if LOG
|
||||
@initWorld()
|
||||
@supermodel.clearMaxProgress()
|
||||
@trigger 'world-necessities-loaded'
|
||||
|
@ -374,7 +376,7 @@ module.exports = class LevelLoader extends CocoClass
|
|||
|
||||
onSupermodelLoaded: ->
|
||||
return if @destroyed
|
||||
console.log 'SuperModel for Level loaded in', new Date().getTime() - @t0, 'ms'
|
||||
console.log 'SuperModel for Level loaded in', new Date().getTime() - @t0, 'ms' if LOG
|
||||
@loadLevelSounds()
|
||||
@denormalizeSession()
|
||||
|
||||
|
@ -482,7 +484,7 @@ module.exports = class LevelLoader extends CocoClass
|
|||
@world.difficulty = Math.max 0, @world.difficulty - 1 # Show the difficulty they won, not the next one.
|
||||
serializedLevel = @level.serialize(@supermodel, @session, @opponentSession)
|
||||
@world.loadFromLevel serializedLevel, false
|
||||
console.log 'World has been initialized from level loader.'
|
||||
console.log 'World has been initialized from level loader.' if LOG
|
||||
|
||||
# Initial Sound Loading
|
||||
|
||||
|
|
|
@ -12,20 +12,18 @@ module.exports =
|
|||
continue if not instance
|
||||
instance.numCompleted = 0
|
||||
instance.started = false
|
||||
levels = classroom.getLevels({courseID: course.id, withoutLadderLevels: true})
|
||||
levels = classroom.getLevels({courseID: course.id})
|
||||
for userID in instance.get('members')
|
||||
instance.started ||= _.any levels.models, (level) ->
|
||||
return false if level.isLadder()
|
||||
session = _.find classroom.sessions.models, (session) ->
|
||||
session.get('creator') is userID and session.get('level').original is level.get('original')
|
||||
session?
|
||||
levelCompletes = _.map levels.models, (level) ->
|
||||
return true if level.isLadder()
|
||||
#TODO: Hella slow! Do the mapping first!
|
||||
session = _.find classroom.sessions.models, (session) ->
|
||||
sessions = _.filter classroom.sessions.models, (session) ->
|
||||
session.get('creator') is userID and session.get('level').original is level.get('original')
|
||||
# sessionMap[userID][level].completed()
|
||||
session?.completed()
|
||||
_.find(sessions, (s) -> s.completed())
|
||||
if _.every levelCompletes
|
||||
instance.numCompleted += 1
|
||||
|
||||
|
@ -34,14 +32,14 @@ module.exports =
|
|||
for course, courseIndex in courses.models
|
||||
instance = courseInstances.findWhere({ courseID: course.id, classroomID: classroom.id })
|
||||
continue if not instance
|
||||
levels = classroom.getLevels({courseID: course.id, withoutLadderLevels: true})
|
||||
levels = classroom.getLevels({courseID: course.id})
|
||||
for level, levelIndex in levels.models
|
||||
userIDs = []
|
||||
for user in students.models
|
||||
userID = user.id
|
||||
session = _.find classroom.sessions.models, (session) ->
|
||||
sessions = _.filter classroom.sessions.models, (session) ->
|
||||
session.get('creator') is userID and session.get('level').original is level.get('original')
|
||||
if not session?.completed()
|
||||
if not _.find(sessions, (s) -> s.completed())
|
||||
userIDs.push userID
|
||||
if userIDs.length > 0
|
||||
users = _.map userIDs, (id) ->
|
||||
|
@ -61,16 +59,16 @@ module.exports =
|
|||
courseIndex = courses.models.length - courseIndex - 1 #compensate for reverse
|
||||
instance = courseInstances.findWhere({ courseID: course.id, classroomID: classroom.id })
|
||||
continue if not instance
|
||||
levels = classroom.getLevels({courseID: course.id, withoutLadderLevels: true})
|
||||
levels = classroom.getLevels({courseID: course.id})
|
||||
levelModels = levels.models.slice()
|
||||
for level, levelIndex in levelModels.reverse() #
|
||||
levelIndex = levelModels.length - levelIndex - 1 #compensate for reverse
|
||||
userIDs = []
|
||||
for user in students.models
|
||||
userID = user.id
|
||||
session = _.find classroom.sessions.models, (session) ->
|
||||
sessions = _.filter classroom.sessions.models, (session) ->
|
||||
session.get('creator') is userID and session.get('level').original is level.get('original')
|
||||
if session?.completed() #
|
||||
if _.find(sessions, (s) -> s.completed()) #
|
||||
userIDs.push userID
|
||||
if userIDs.length > 0
|
||||
users = _.map userIDs, (id) ->
|
||||
|
@ -91,7 +89,7 @@ module.exports =
|
|||
conceptData[classroom.id] = {}
|
||||
|
||||
for course, courseIndex in courses.models
|
||||
levels = classroom.getLevels({courseID: course.id, withoutLadderLevels: true})
|
||||
levels = classroom.getLevels({courseID: course.id})
|
||||
|
||||
for level in levels.models
|
||||
levelID = level.get('original')
|
||||
|
@ -102,16 +100,16 @@ module.exports =
|
|||
|
||||
for concept in level.get('concepts')
|
||||
for userID in classroom.get('members')
|
||||
session = _.find classroom.sessions.models, (session) ->
|
||||
sessions = _.filter classroom.sessions.models, (session) ->
|
||||
session.get('creator') is userID and session.get('level').original is levelID
|
||||
|
||||
if not session # haven't gotten to this level yet, but might have completed others before
|
||||
if _.size(sessions) is 0 # haven't gotten to this level yet, but might have completed others before
|
||||
for concept in level.get('concepts')
|
||||
conceptData[classroom.id][concept].completed = false
|
||||
if session # have gotten to the level and at least started it
|
||||
if _.size(sessions) > 0 # have gotten to the level and at least started it
|
||||
for concept in level.get('concepts')
|
||||
conceptData[classroom.id][concept].started = true
|
||||
if not session?.completed() # level started but not completed
|
||||
if not _.find(sessions, (s) -> s.completed()) # level started but not completed
|
||||
for concept in level.get('concepts')
|
||||
conceptData[classroom.id][concept].completed = false
|
||||
conceptData
|
||||
|
@ -139,7 +137,7 @@ module.exports =
|
|||
continue
|
||||
progressData[classroom.id][course.id] = { completed: true, started: false } # to be updated
|
||||
|
||||
levels = classroom.getLevels({courseID: course.id, withoutLadderLevels: true})
|
||||
levels = classroom.getLevels({courseID: course.id})
|
||||
for level in levels.models
|
||||
levelID = level.get('original')
|
||||
progressData[classroom.id][course.id][levelID] = {
|
||||
|
@ -154,12 +152,12 @@ module.exports =
|
|||
courseProgress = progressData[classroom.id][course.id]
|
||||
courseProgress[userID] ?= { completed: true, started: false, levelsCompleted: 0 } # Only set it the first time through a user
|
||||
courseProgress[levelID][userID] = { completed: true, started: false } # These don't matter, will always be set
|
||||
session = _.find classroom.sessions.models, (session) ->
|
||||
sessions = _.filter classroom.sessions.models, (session) ->
|
||||
session.get('creator') is userID and session.get('level').original is levelID
|
||||
|
||||
courseProgress[levelID][userID].session = session
|
||||
|
||||
if not session # haven't gotten to this level yet, but might have completed others before
|
||||
courseProgress[levelID][userID].session = _.find(sessions, (s) -> s.completed()) or _.first(sessions)
|
||||
|
||||
if _.size(sessions) is 0 # haven't gotten to this level yet, but might have completed others before
|
||||
courseProgress.started ||= false #no-op
|
||||
courseProgress.completed = false
|
||||
courseProgress[userID].started ||= false #no-op
|
||||
|
@ -169,22 +167,23 @@ module.exports =
|
|||
courseProgress[levelID][userID].started = false
|
||||
courseProgress[levelID][userID].completed = false
|
||||
|
||||
if session # have gotten to the level and at least started it
|
||||
if _.size(sessions) > 0 # have gotten to the level and at least started it
|
||||
courseProgress.started = true
|
||||
courseProgress[userID].started = true
|
||||
courseProgress[levelID].started = true
|
||||
courseProgress[levelID][userID].started = true
|
||||
courseProgress[levelID][userID].lastPlayed = new Date(session.get('changed'))
|
||||
courseProgress[levelID][userID].lastPlayed = new Date(Math.max(_.map(sessions, 'changed')))
|
||||
courseProgress[levelID].numStarted += 1
|
||||
|
||||
if session?.completed() # have finished this level
|
||||
if _.find(sessions, (s) -> s.completed()) # have finished this level
|
||||
courseProgress.completed &&= true #no-op
|
||||
courseProgress[userID].completed &&= true #no-op
|
||||
courseProgress[userID].levelsCompleted += 1
|
||||
courseProgress[levelID].completed &&= true #no-op
|
||||
# courseProgress[levelID].numCompleted += 1
|
||||
courseProgress[levelID][userID].completed = true
|
||||
courseProgress[levelID][userID].dateFirstCompleted = new Date(session.get('dateFirstCompleted') || session.get('changed'))
|
||||
dates = (s.get('dateFirstCompleted') || s.get('changed') for s in sessions)
|
||||
courseProgress[levelID][userID].dateFirstCompleted = new Date(Math.max(dates...))
|
||||
else # level started but not completed
|
||||
courseProgress.completed = false
|
||||
courseProgress[userID].completed = false
|
||||
|
|
|
@ -124,10 +124,11 @@ class CocoModel extends Backbone.Model
|
|||
validate: ->
|
||||
errors = @getValidationErrors()
|
||||
if errors?.length
|
||||
console.debug "Validation failed for #{@constructor.className}: '#{@get('name') or @}'."
|
||||
for error in errors
|
||||
console.debug "\t", error.dataPath, ':', error.message
|
||||
console.trace?()
|
||||
unless application.testing
|
||||
console.debug "Validation failed for #{@constructor.className}: '#{@get('name') or @}'."
|
||||
for error in errors
|
||||
console.debug "\t", error.dataPath, ':', error.message
|
||||
console.trace?()
|
||||
return errors
|
||||
|
||||
save: (attrs, options) ->
|
||||
|
@ -188,7 +189,6 @@ class CocoModel extends Backbone.Model
|
|||
keys.push key
|
||||
|
||||
return unless keys.length
|
||||
console.debug 'Patching', @get('name') or @, keys
|
||||
@save(attrs, options)
|
||||
|
||||
fetch: (options) ->
|
||||
|
|
|
@ -41,7 +41,7 @@ module.exports = class LevelSession extends CocoModel
|
|||
@get('submittedCodeLanguage')? and @get('team')?
|
||||
|
||||
completed: ->
|
||||
@get('state')?.complete || false
|
||||
@get('state')?.complete || @get('submitted') || false
|
||||
|
||||
shouldAvoidCorruptData: (attrs) ->
|
||||
return false unless me.team is 'humans'
|
||||
|
|
|
@ -10,7 +10,6 @@ block content
|
|||
a(href="/account", data-i18n="nav.account")
|
||||
li.active(data-i18n="account.payments")
|
||||
|
||||
- console.log('render', view.payments.size())
|
||||
if view.payments.size()
|
||||
table.table.table-striped
|
||||
tr
|
||||
|
|
|
@ -300,7 +300,7 @@ mixin courseProgressTab
|
|||
|
||||
mixin courseOverview
|
||||
- var course = state.get('selectedCourse')
|
||||
- var levels = view.classroom.getLevels({courseID: course.id, withoutLadderLevels: true}).models
|
||||
- var levels = view.classroom.getLevels({courseID: course.id}).models
|
||||
.course-overview-row
|
||||
.course-title.student-name
|
||||
span= course.get('name')
|
||||
|
@ -318,7 +318,7 @@ mixin studentLevelsRow(student)
|
|||
div.student-email.small-details= student.get('email')
|
||||
div.student-levels-progress
|
||||
- var course = state.get('selectedCourse')
|
||||
- var levels = view.classroom.getLevels({courseID: course.id, withoutLadderLevels: true}).models
|
||||
- var levels = view.classroom.getLevels({courseID: course.id}).models
|
||||
each level, index in levels
|
||||
- var progress = state.get('progressData').get({ classroom: view.classroom, course: course, level: level, user: student })
|
||||
+studentLevelProgressDot(progress, level, index+1, session)
|
||||
|
|
|
@ -22,7 +22,7 @@ module.exports =
|
|||
fetchByCode: wrap (req, res, next) ->
|
||||
code = req.query.code
|
||||
return next() unless code
|
||||
classroom = yield Classroom.findOne({ code: code.toLowerCase().replace(/ /g, '') }).select('name ownerID aceConfig')
|
||||
classroom = yield Classroom.findOne({ code: code.toLowerCase().replace(RegExp(' ', 'g') , '') }).select('name ownerID aceConfig')
|
||||
if not classroom
|
||||
log.debug("classrooms.fetchByCode: Couldn't find Classroom with code: #{code}")
|
||||
throw new errors.NotFound('Classroom not found.')
|
||||
|
@ -104,7 +104,7 @@ module.exports =
|
|||
members = classroom.get('members') or []
|
||||
members = members.slice(memberSkip, memberSkip + memberLimit)
|
||||
dbqs = []
|
||||
select = 'state.complete level creator playtime changed dateFirstCompleted'
|
||||
select = 'state.complete level creator playtime changed dateFirstCompleted submitted'
|
||||
for member in members
|
||||
dbqs.push(LevelSession.find({creator: member.toHexString()}).select(select).exec())
|
||||
results = yield dbqs
|
||||
|
@ -170,7 +170,7 @@ module.exports =
|
|||
if req.user.isTeacher()
|
||||
log.debug("classrooms.join: Cannot join a classroom as a teacher: #{req.user.id}")
|
||||
throw new errors.Forbidden('Cannot join a classroom as a teacher')
|
||||
code = req.body.code.toLowerCase().replace(/ /g, '')
|
||||
code = req.body.code.toLowerCase().replace(RegExp(' ', 'g'), '')
|
||||
classroom = yield Classroom.findOne({code: code})
|
||||
if not classroom
|
||||
log.debug("classrooms.join: Classroom not found with code #{code}")
|
||||
|
|
|
@ -36,7 +36,6 @@ describe 'CoursesHelper', ->
|
|||
describe 'progressData.get({classroom, course})', ->
|
||||
it 'returns object with .completed=true and .started=true', ->
|
||||
progressData = helper.calculateAllProgress(@classrooms, @courses, @courseInstances, @members)
|
||||
console.log 'progress data?', progressData
|
||||
progress = progressData.get {@classroom, @course}
|
||||
expect(progress.completed).toBe true
|
||||
expect(progress.started).toBe true
|
||||
|
|
Loading…
Reference in a new issue