Include ladder levels in level stats in teacher views, clean client test logs

This commit is contained in:
Scott Erickson 2016-06-17 15:15:13 -07:00
parent 490ea8d1bc
commit 514fce349a
8 changed files with 43 additions and 44 deletions

View file

@ -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

View file

@ -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
courseProgress[levelID][userID].session = _.find(sessions, (s) -> s.completed()) or _.first(sessions)
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
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

View file

@ -124,6 +124,7 @@ class CocoModel extends Backbone.Model
validate: ->
errors = @getValidationErrors()
if errors?.length
unless application.testing
console.debug "Validation failed for #{@constructor.className}: '#{@get('name') or @}'."
for error in errors
console.debug "\t", error.dataPath, ':', error.message
@ -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) ->

View file

@ -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'

View file

@ -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

View file

@ -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)

View file

@ -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}")

View file

@ -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