2016-04-13 09:54:24 -07:00
Levels = require ' collections/Levels '
2016-03-30 13:57:19 -07:00
module.exports =
# Result: Each course instance gains a property, numCompleted, that is the
# number of students in that course instance who have completed ALL of
# the levels in thate course
2016-04-13 09:54:24 -07:00
calculateDots: (classrooms, courses, courseInstances) ->
2016-03-30 13:57:19 -07:00
for classroom in classrooms . models
# map [user, level] => session so we don't have to do find TODO
for course , courseIndex in courses . models
instance = courseInstances . findWhere ( { courseID: course . id , classroomID: classroom . id } )
continue if not instance
instance.numCompleted = 0
2016-05-20 14:52:04 -07:00
instance.started = false
2016-04-13 09:54:24 -07:00
levels = classroom . getLevels ( { courseID: course . id , withoutLadderLevels: true } )
2016-03-30 13:57:19 -07:00
for userID in instance . get ( ' members ' )
2016-05-24 16:59:36 -07:00
instance . started || = _ . any levels . models , (level) ->
2016-05-20 14:52:04 -07:00
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 ?
2016-04-13 09:54:24 -07:00
levelCompletes = _ . map levels . models , (level) ->
2016-03-30 13:57:19 -07:00
return true if level . isLadder ( )
#TODO: Hella slow! Do the mapping first!
session = _ . find classroom . sessions . models , (session) ->
session . get ( ' creator ' ) is userID and session . get ( ' level ' ) . original is level . get ( ' original ' )
# sessionMap[userID][level].completed()
session ? . completed ( )
2016-03-30 16:20:37 -07:00
if _ . every levelCompletes
2016-03-30 13:57:19 -07:00
instance . numCompleted += 1
2016-04-13 09:54:24 -07:00
calculateEarliestIncomplete: (classroom, courses, courseInstances, students) ->
2016-03-30 13:57:19 -07:00
# Loop through all the combinations of things, return the first one that somebody hasn't finished
for course , courseIndex in courses . models
instance = courseInstances . findWhere ( { courseID: course . id , classroomID: classroom . id } )
continue if not instance
2016-04-13 09:54:24 -07:00
levels = classroom . getLevels ( { courseID: course . id , withoutLadderLevels: true } )
for level , levelIndex in levels . models
2016-03-30 13:57:19 -07:00
userIDs = [ ]
for user in students . models
userID = user . id
session = _ . find classroom . sessions . models , (session) ->
session . get ( ' creator ' ) is userID and session . get ( ' level ' ) . original is level . get ( ' original ' )
if not session ? . completed ( )
userIDs . push userID
if userIDs . length > 0
users = _ . map userIDs , (id) ->
students . get ( id )
return {
courseNumber: courseIndex + 1
levelNumber: levelIndex + 1
levelName: level . get ( ' name ' )
users: users
}
null
2016-04-13 09:54:24 -07:00
calculateLatestComplete: (classroom, courses, courseInstances, students) ->
2016-03-30 13:57:19 -07:00
# Loop through all the combinations of things in reverse order, return the level that anyone's finished
courseModels = courses . models . slice ( )
for course , courseIndex in courseModels . reverse ( ) #
courseIndex = courses . models . length - courseIndex - 1 #compensate for reverse
instance = courseInstances . findWhere ( { courseID: course . id , classroomID: classroom . id } )
continue if not instance
2016-04-13 09:54:24 -07:00
levels = classroom . getLevels ( { courseID: course . id , withoutLadderLevels: true } )
levelModels = levels . models . slice ( )
2016-03-30 13:57:19 -07:00
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) ->
session . get ( ' creator ' ) is userID and session . get ( ' level ' ) . original is level . get ( ' original ' )
if session ? . completed ( ) #
userIDs . push userID
if userIDs . length > 0
users = _ . map userIDs , (id) ->
students . get ( id )
return {
courseNumber: courseIndex + 1
levelNumber: levelIndex + 1
levelName: level . get ( ' name ' )
users: users
}
null
calculateConceptsCovered: (classrooms, courses, campaigns, courseInstances, students) ->
# Loop through all level/user combination and record
# whether they've started, and completed, each concept
conceptData = { }
for classroom in classrooms . models
conceptData [ classroom . id ] = { }
for course , courseIndex in courses . models
2016-04-13 09:54:24 -07:00
levels = classroom . getLevels ( { courseID: course . id , withoutLadderLevels: true } )
2016-03-30 13:57:19 -07:00
2016-04-13 09:54:24 -07:00
for level in levels . models
2016-03-30 13:57:19 -07:00
levelID = level . get ( ' original ' )
for concept in level . get ( ' concepts ' )
unless conceptData [ classroom . id ] [ concept ]
conceptData [ classroom . id ] [ concept ] = { completed: true , started: false }
for concept in level . get ( ' concepts ' )
for userID in classroom . get ( ' members ' )
session = _ . find 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
for concept in level . get ( ' concepts ' )
conceptData [ classroom . id ] [ concept ] . completed = false
if session # 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
for concept in level . get ( ' concepts ' )
conceptData [ classroom . id ] [ concept ] . completed = false
conceptData
2016-04-13 09:54:24 -07:00
calculateAllProgress: (classrooms, courses, courseInstances, students) ->
2016-03-30 13:57:19 -07:00
# Loop through all combinations and record:
# Completeness for each student/course
# Completeness for each student/level
# Completeness for each class/course (across all students)
# Completeness for each class/level (across all students)
# class -> course
# class -> course -> student
# class -> course -> level
# class -> course -> level -> student
progressData = { }
for classroom in classrooms . models
progressData [ classroom . id ] = { }
for course , courseIndex in courses . models
instance = courseInstances . findWhere ( { courseID: course . id , classroomID: classroom . id } )
if not instance
progressData [ classroom . id ] [ course . id ] = { completed: false , started: false }
continue
progressData [ classroom . id ] [ course . id ] = { completed: true , started: false } # to be updated
2016-04-13 09:54:24 -07:00
levels = classroom . getLevels ( { courseID: course . id , withoutLadderLevels: true } )
for level in levels . models
2016-03-30 13:57:19 -07:00
levelID = level . get ( ' original ' )
2016-04-19 13:44:48 -07:00
progressData [ classroom . id ] [ course . id ] [ levelID ] = {
completed: students . size ( ) > 0 ,
started: false
numStarted: 0
# numCompleted: 0
}
2016-03-30 13:57:19 -07:00
for user in students . models
userID = user . id
courseProgress = progressData [ classroom . id ] [ course . id ]
2016-04-19 13:44:48 -07:00
courseProgress [ userID ] ? = { completed: true , started: false , levelsCompleted: 0 } # Only set it the first time through a user
2016-03-30 13:57:19 -07:00
courseProgress [ levelID ] [ userID ] = { completed: true , started: false } # These don't matter, will always be set
session = _ . find classroom . sessions . models , (session) ->
session . get ( ' creator ' ) is userID and session . get ( ' level ' ) . original is levelID
2016-04-19 13:44:48 -07:00
2016-03-30 13:57:19 -07:00
if not session # 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
courseProgress [ userID ] . completed = false
courseProgress [ levelID ] . started || = false #no-op
courseProgress [ levelID ] . completed = false
courseProgress [ levelID ] [ userID ] . started = false
courseProgress [ levelID ] [ userID ] . completed = false
2016-04-19 13:44:48 -07:00
2016-03-30 13:57:19 -07:00
if session # 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
2016-04-19 13:44:48 -07:00
courseProgress [ levelID ] [ userID ] . lastPlayed = new Date ( session . get ( ' changed ' ) )
courseProgress [ levelID ] . numStarted += 1
2016-03-30 13:57:19 -07:00
if session ? . completed ( ) # have finished this level
courseProgress . completed && = true #no-op
2016-04-19 13:44:48 -07:00
courseProgress [ userID ] . completed && = true #no-op
courseProgress [ userID ] . levelsCompleted += 1
2016-03-30 13:57:19 -07:00
courseProgress [ levelID ] . completed && = true #no-op
2016-04-19 13:44:48 -07:00
# courseProgress[levelID].numCompleted += 1
2016-03-30 13:57:19 -07:00
courseProgress [ levelID ] [ userID ] . completed = true
2016-04-19 13:44:48 -07:00
courseProgress [ levelID ] [ userID ] . dateFirstCompleted = new Date ( session . get ( ' dateFirstCompleted ' ) || session . get ( ' changed ' ) )
2016-03-30 13:57:19 -07:00
else # level started but not completed
courseProgress.completed = false
courseProgress [ userID ] . completed = false
courseProgress [ levelID ] . completed = false
courseProgress [ levelID ] [ userID ] . completed = false
2016-04-19 13:44:48 -07:00
courseProgress [ levelID ] . dateFirstCompleted = null
courseProgress [ levelID ] [ userID ] . dateFirstCompleted = null
2016-03-30 13:57:19 -07:00
_ . assign ( progressData , progressMixin )
return progressData
progressMixin =
get: (options={}) ->
{ classroom , course , level , user } = options
throw new Error " You must provide a classroom " unless classroom
throw new Error " You must provide a course " unless course
defaultValue = { completed: false , started: false }
if options . level
levelID = level . get ( ' original ' )
if options . user
return @ [ classroom . id ] ? [ course . id ] ? [ levelID ] ? [ user . id ] or defaultValue
else
return @ [ classroom . id ] ? [ course . id ] ? [ levelID ] or defaultValue
else
if options . user
return @ [ classroom . id ] ? [ course . id ] ? [ user . id ] or defaultValue
else
return @ [ classroom . id ] ? [ course . id ] or defaultValue