codecombat/app/lib/coursesHelper.coffee

230 lines
11 KiB
CoffeeScript
Raw Normal View History

2016-04-13 12:54:24 -04:00
Levels = require 'collections/Levels'
2016-03-30 16:57:19 -04: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
# TODO: simplify, classroom.sessions only includes sessions for assigned courses now
2016-04-13 12:54:24 -04:00
calculateDots: (classrooms, courses, courseInstances) ->
2016-03-30 16:57:19 -04: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
instance.started = false
levels = classroom.getLevels({courseID: course.id})
levels.remove(levels.filter((level) => level.get('practice')))
2016-03-30 16:57:19 -04:00
for userID in instance.get('members')
2016-05-24 19:59:36 -04:00
instance.started ||= _.any levels.models, (level) ->
session = _.find classroom.sessions.models, (session) ->
session.get('creator') is userID and session.get('level').original is level.get('original')
session?
2016-04-13 12:54:24 -04:00
levelCompletes = _.map levels.models, (level) ->
2016-03-30 16:57:19 -04:00
#TODO: Hella slow! Do the mapping first!
sessions = _.filter classroom.sessions.models, (session) ->
2016-03-30 16:57:19 -04:00
session.get('creator') is userID and session.get('level').original is level.get('original')
# sessionMap[userID][level].completed()
_.find(sessions, (s) -> s.completed())
if _.every levelCompletes
2016-03-30 16:57:19 -04:00
instance.numCompleted += 1
2016-04-13 12:54:24 -04:00
calculateEarliestIncomplete: (classroom, courses, courseInstances, students) ->
2016-03-30 16:57:19 -04: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
levels = classroom.getLevels({courseID: course.id})
2016-04-13 12:54:24 -04:00
for level, levelIndex in levels.models
2016-03-30 16:57:19 -04:00
userIDs = []
for user in students.models
userID = user.id
sessions = _.filter classroom.sessions.models, (session) ->
2016-03-30 16:57:19 -04:00
session.get('creator') is userID and session.get('level').original is level.get('original')
if not _.find(sessions, (s) -> s.completed())
2016-03-30 16:57:19 -04:00
userIDs.push userID
if userIDs.length > 0
users = _.map userIDs, (id) ->
students.get(id)
return {
courseName: course.get('name')
2016-03-30 16:57:19 -04:00
courseNumber: courseIndex + 1
levelNumber: levelIndex + 1
levelName: level.get('name')
users: users
}
null
2016-04-13 12:54:24 -04:00
calculateLatestComplete: (classroom, courses, courseInstances, students) ->
2016-03-30 16:57:19 -04: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
levels = classroom.getLevels({courseID: course.id})
2016-04-13 12:54:24 -04:00
levelModels = levels.models.slice()
2016-03-30 16:57:19 -04:00
for level, levelIndex in levelModels.reverse() #
levelIndex = levelModels.length - levelIndex - 1 #compensate for reverse
userIDs = []
for user in students.models
userID = user.id
sessions = _.filter classroom.sessions.models, (session) ->
2016-03-30 16:57:19 -04:00
session.get('creator') is userID and session.get('level').original is level.get('original')
if _.find(sessions, (s) -> s.completed()) #
2016-03-30 16:57:19 -04:00
userIDs.push userID
if userIDs.length > 0
users = _.map userIDs, (id) ->
students.get(id)
return {
courseName: course.get('name')
2016-03-30 16:57:19 -04:00
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
levels = classroom.getLevels({courseID: course.id})
2016-03-30 16:57:19 -04:00
2016-04-13 12:54:24 -04:00
for level in levels.models
2016-03-30 16:57:19 -04: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')
sessions = _.filter classroom.sessions.models, (session) ->
2016-03-30 16:57:19 -04:00
session.get('creator') is userID and session.get('level').original is levelID
if _.size(sessions) is 0 # haven't gotten to this level yet, but might have completed others before
2016-03-30 16:57:19 -04:00
for concept in level.get('concepts')
conceptData[classroom.id][concept].completed = false
if _.size(sessions) > 0 # have gotten to the level and at least started it
2016-03-30 16:57:19 -04:00
for concept in level.get('concepts')
conceptData[classroom.id][concept].started = true
if not _.find(sessions, (s) -> s.completed()) # level started but not completed
2016-03-30 16:57:19 -04:00
for concept in level.get('concepts')
conceptData[classroom.id][concept].completed = false
conceptData
2016-04-13 12:54:24 -04:00
calculateAllProgress: (classrooms, courses, courseInstances, students) ->
2016-03-30 16:57:19 -04: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 12:54:24 -04:00
levels = classroom.getLevels({courseID: course.id})
2016-04-13 12:54:24 -04:00
for level in levels.models
2016-03-30 16:57:19 -04:00
levelID = level.get('original')
Refactor and update teacher-dashboard This updates TeacherClassView and ActivateLicensesModal to use the new state-based rendering system, making it much snappier and less clunky feeling, and improving data consistency. Features also included in this: - Hover details for progress dots in TeacherClassView - ActivateLicensesModal has an "All Students" option and better handling when you switch classrooms in the dropdown - Unenrolled/Unassigned students are shown separately in Course Progress and can be enrolled/assigned from there. Add Back to Classes button on demo-request submitted view Delete temporary patch file Show unenrolled students separately in Course Progress (incomplete) Migrate TeacherClassView to use orchestrator-style events, add unassigned students section, replace bootstrap tabs with state-based tabs Convert missed instance variables to be in @state Fix merge errors (in progress) Convert a bunch of stuff to use state and events (removing student needs fixing) Fix up modal interactions, some bugs Switch state to be a Model, sync up course dropdowns Convert student sorting to use state model Add hover tooltips to TeacherClassView Students tab Don't keep tooltip open when you mouse into it Add dateFirstCompleted and Course Progress tooltips Course Overview progress tooltips Refactor ActivateLicensesModal Refactors: Uses state object for view state Passes back the updated users in 'redeem-users' event instead of modifying given collection Features: Add 'All Students' dropdown option Don't forget checked students if you change classroom from dropdown, but only enroll the ones visible when you click "Enroll (n) Students" Separate enrolled students; improve style Rearrange error text Disable enroll-students button when none are selected Remove console.logs Move style-flat variables to another file This prevents .style-flat from being copied in multiple times to the resulting CSS. Show Unarchive button when on the page for an archived class Move text to en.coffee Only sort students on first classroom sync Fix merge error Handle sessions missing completion date in view logic instead of migration script Listen to classroom sync more than once in case it gets unarchived
2016-04-19 16:44:48 -04:00
progressData[classroom.id][course.id][levelID] = {
completed: students.size() > 0,
started: false
numStarted: 0
# numCompleted: 0
}
2016-03-30 16:57:19 -04:00
for user in students.models
userID = user.id
courseProgress = progressData[classroom.id][course.id]
Refactor and update teacher-dashboard This updates TeacherClassView and ActivateLicensesModal to use the new state-based rendering system, making it much snappier and less clunky feeling, and improving data consistency. Features also included in this: - Hover details for progress dots in TeacherClassView - ActivateLicensesModal has an "All Students" option and better handling when you switch classrooms in the dropdown - Unenrolled/Unassigned students are shown separately in Course Progress and can be enrolled/assigned from there. Add Back to Classes button on demo-request submitted view Delete temporary patch file Show unenrolled students separately in Course Progress (incomplete) Migrate TeacherClassView to use orchestrator-style events, add unassigned students section, replace bootstrap tabs with state-based tabs Convert missed instance variables to be in @state Fix merge errors (in progress) Convert a bunch of stuff to use state and events (removing student needs fixing) Fix up modal interactions, some bugs Switch state to be a Model, sync up course dropdowns Convert student sorting to use state model Add hover tooltips to TeacherClassView Students tab Don't keep tooltip open when you mouse into it Add dateFirstCompleted and Course Progress tooltips Course Overview progress tooltips Refactor ActivateLicensesModal Refactors: Uses state object for view state Passes back the updated users in 'redeem-users' event instead of modifying given collection Features: Add 'All Students' dropdown option Don't forget checked students if you change classroom from dropdown, but only enroll the ones visible when you click "Enroll (n) Students" Separate enrolled students; improve style Rearrange error text Disable enroll-students button when none are selected Remove console.logs Move style-flat variables to another file This prevents .style-flat from being copied in multiple times to the resulting CSS. Show Unarchive button when on the page for an archived class Move text to en.coffee Only sort students on first classroom sync Fix merge error Handle sessions missing completion date in view logic instead of migration script Listen to classroom sync more than once in case it gets unarchived
2016-04-19 16:44:48 -04:00
courseProgress[userID] ?= { completed: true, started: false, levelsCompleted: 0 } # Only set it the first time through a user
2016-03-30 16:57:19 -04:00
courseProgress[levelID][userID] = { completed: true, started: false } # These don't matter, will always be set
sessions = _.filter classroom.sessions.models, (session) ->
2016-03-30 16:57:19 -04:00
session.get('creator') is userID and session.get('level').original is levelID
Refactor and update teacher-dashboard This updates TeacherClassView and ActivateLicensesModal to use the new state-based rendering system, making it much snappier and less clunky feeling, and improving data consistency. Features also included in this: - Hover details for progress dots in TeacherClassView - ActivateLicensesModal has an "All Students" option and better handling when you switch classrooms in the dropdown - Unenrolled/Unassigned students are shown separately in Course Progress and can be enrolled/assigned from there. Add Back to Classes button on demo-request submitted view Delete temporary patch file Show unenrolled students separately in Course Progress (incomplete) Migrate TeacherClassView to use orchestrator-style events, add unassigned students section, replace bootstrap tabs with state-based tabs Convert missed instance variables to be in @state Fix merge errors (in progress) Convert a bunch of stuff to use state and events (removing student needs fixing) Fix up modal interactions, some bugs Switch state to be a Model, sync up course dropdowns Convert student sorting to use state model Add hover tooltips to TeacherClassView Students tab Don't keep tooltip open when you mouse into it Add dateFirstCompleted and Course Progress tooltips Course Overview progress tooltips Refactor ActivateLicensesModal Refactors: Uses state object for view state Passes back the updated users in 'redeem-users' event instead of modifying given collection Features: Add 'All Students' dropdown option Don't forget checked students if you change classroom from dropdown, but only enroll the ones visible when you click "Enroll (n) Students" Separate enrolled students; improve style Rearrange error text Disable enroll-students button when none are selected Remove console.logs Move style-flat variables to another file This prevents .style-flat from being copied in multiple times to the resulting CSS. Show Unarchive button when on the page for an archived class Move text to en.coffee Only sort students on first classroom sync Fix merge error Handle sessions missing completion date in view logic instead of migration script Listen to classroom sync more than once in case it gets unarchived
2016-04-19 16:44:48 -04:00
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
2016-03-30 16:57:19 -04:00
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
Refactor and update teacher-dashboard This updates TeacherClassView and ActivateLicensesModal to use the new state-based rendering system, making it much snappier and less clunky feeling, and improving data consistency. Features also included in this: - Hover details for progress dots in TeacherClassView - ActivateLicensesModal has an "All Students" option and better handling when you switch classrooms in the dropdown - Unenrolled/Unassigned students are shown separately in Course Progress and can be enrolled/assigned from there. Add Back to Classes button on demo-request submitted view Delete temporary patch file Show unenrolled students separately in Course Progress (incomplete) Migrate TeacherClassView to use orchestrator-style events, add unassigned students section, replace bootstrap tabs with state-based tabs Convert missed instance variables to be in @state Fix merge errors (in progress) Convert a bunch of stuff to use state and events (removing student needs fixing) Fix up modal interactions, some bugs Switch state to be a Model, sync up course dropdowns Convert student sorting to use state model Add hover tooltips to TeacherClassView Students tab Don't keep tooltip open when you mouse into it Add dateFirstCompleted and Course Progress tooltips Course Overview progress tooltips Refactor ActivateLicensesModal Refactors: Uses state object for view state Passes back the updated users in 'redeem-users' event instead of modifying given collection Features: Add 'All Students' dropdown option Don't forget checked students if you change classroom from dropdown, but only enroll the ones visible when you click "Enroll (n) Students" Separate enrolled students; improve style Rearrange error text Disable enroll-students button when none are selected Remove console.logs Move style-flat variables to another file This prevents .style-flat from being copied in multiple times to the resulting CSS. Show Unarchive button when on the page for an archived class Move text to en.coffee Only sort students on first classroom sync Fix merge error Handle sessions missing completion date in view logic instead of migration script Listen to classroom sync more than once in case it gets unarchived
2016-04-19 16:44:48 -04:00
if _.size(sessions) > 0 # have gotten to the level and at least started it
2016-03-30 16:57:19 -04:00
courseProgress.started = true
courseProgress[userID].started = true
courseProgress[levelID].started = true
courseProgress[levelID][userID].started = true
courseProgress[levelID][userID].lastPlayed = new Date(Math.max(_.map(sessions, 'changed')))
Refactor and update teacher-dashboard This updates TeacherClassView and ActivateLicensesModal to use the new state-based rendering system, making it much snappier and less clunky feeling, and improving data consistency. Features also included in this: - Hover details for progress dots in TeacherClassView - ActivateLicensesModal has an "All Students" option and better handling when you switch classrooms in the dropdown - Unenrolled/Unassigned students are shown separately in Course Progress and can be enrolled/assigned from there. Add Back to Classes button on demo-request submitted view Delete temporary patch file Show unenrolled students separately in Course Progress (incomplete) Migrate TeacherClassView to use orchestrator-style events, add unassigned students section, replace bootstrap tabs with state-based tabs Convert missed instance variables to be in @state Fix merge errors (in progress) Convert a bunch of stuff to use state and events (removing student needs fixing) Fix up modal interactions, some bugs Switch state to be a Model, sync up course dropdowns Convert student sorting to use state model Add hover tooltips to TeacherClassView Students tab Don't keep tooltip open when you mouse into it Add dateFirstCompleted and Course Progress tooltips Course Overview progress tooltips Refactor ActivateLicensesModal Refactors: Uses state object for view state Passes back the updated users in 'redeem-users' event instead of modifying given collection Features: Add 'All Students' dropdown option Don't forget checked students if you change classroom from dropdown, but only enroll the ones visible when you click "Enroll (n) Students" Separate enrolled students; improve style Rearrange error text Disable enroll-students button when none are selected Remove console.logs Move style-flat variables to another file This prevents .style-flat from being copied in multiple times to the resulting CSS. Show Unarchive button when on the page for an archived class Move text to en.coffee Only sort students on first classroom sync Fix merge error Handle sessions missing completion date in view logic instead of migration script Listen to classroom sync more than once in case it gets unarchived
2016-04-19 16:44:48 -04:00
courseProgress[levelID].numStarted += 1
if _.find(sessions, (s) -> s.completed()) # have finished this level
2016-03-30 16:57:19 -04:00
courseProgress.completed &&= true #no-op
Refactor and update teacher-dashboard This updates TeacherClassView and ActivateLicensesModal to use the new state-based rendering system, making it much snappier and less clunky feeling, and improving data consistency. Features also included in this: - Hover details for progress dots in TeacherClassView - ActivateLicensesModal has an "All Students" option and better handling when you switch classrooms in the dropdown - Unenrolled/Unassigned students are shown separately in Course Progress and can be enrolled/assigned from there. Add Back to Classes button on demo-request submitted view Delete temporary patch file Show unenrolled students separately in Course Progress (incomplete) Migrate TeacherClassView to use orchestrator-style events, add unassigned students section, replace bootstrap tabs with state-based tabs Convert missed instance variables to be in @state Fix merge errors (in progress) Convert a bunch of stuff to use state and events (removing student needs fixing) Fix up modal interactions, some bugs Switch state to be a Model, sync up course dropdowns Convert student sorting to use state model Add hover tooltips to TeacherClassView Students tab Don't keep tooltip open when you mouse into it Add dateFirstCompleted and Course Progress tooltips Course Overview progress tooltips Refactor ActivateLicensesModal Refactors: Uses state object for view state Passes back the updated users in 'redeem-users' event instead of modifying given collection Features: Add 'All Students' dropdown option Don't forget checked students if you change classroom from dropdown, but only enroll the ones visible when you click "Enroll (n) Students" Separate enrolled students; improve style Rearrange error text Disable enroll-students button when none are selected Remove console.logs Move style-flat variables to another file This prevents .style-flat from being copied in multiple times to the resulting CSS. Show Unarchive button when on the page for an archived class Move text to en.coffee Only sort students on first classroom sync Fix merge error Handle sessions missing completion date in view logic instead of migration script Listen to classroom sync more than once in case it gets unarchived
2016-04-19 16:44:48 -04:00
courseProgress[userID].completed &&= true #no-op
courseProgress[userID].levelsCompleted += 1 unless level.get('practice')
2016-03-30 16:57:19 -04:00
courseProgress[levelID].completed &&= true #no-op
Refactor and update teacher-dashboard This updates TeacherClassView and ActivateLicensesModal to use the new state-based rendering system, making it much snappier and less clunky feeling, and improving data consistency. Features also included in this: - Hover details for progress dots in TeacherClassView - ActivateLicensesModal has an "All Students" option and better handling when you switch classrooms in the dropdown - Unenrolled/Unassigned students are shown separately in Course Progress and can be enrolled/assigned from there. Add Back to Classes button on demo-request submitted view Delete temporary patch file Show unenrolled students separately in Course Progress (incomplete) Migrate TeacherClassView to use orchestrator-style events, add unassigned students section, replace bootstrap tabs with state-based tabs Convert missed instance variables to be in @state Fix merge errors (in progress) Convert a bunch of stuff to use state and events (removing student needs fixing) Fix up modal interactions, some bugs Switch state to be a Model, sync up course dropdowns Convert student sorting to use state model Add hover tooltips to TeacherClassView Students tab Don't keep tooltip open when you mouse into it Add dateFirstCompleted and Course Progress tooltips Course Overview progress tooltips Refactor ActivateLicensesModal Refactors: Uses state object for view state Passes back the updated users in 'redeem-users' event instead of modifying given collection Features: Add 'All Students' dropdown option Don't forget checked students if you change classroom from dropdown, but only enroll the ones visible when you click "Enroll (n) Students" Separate enrolled students; improve style Rearrange error text Disable enroll-students button when none are selected Remove console.logs Move style-flat variables to another file This prevents .style-flat from being copied in multiple times to the resulting CSS. Show Unarchive button when on the page for an archived class Move text to en.coffee Only sort students on first classroom sync Fix merge error Handle sessions missing completion date in view logic instead of migration script Listen to classroom sync more than once in case it gets unarchived
2016-04-19 16:44:48 -04:00
# courseProgress[levelID].numCompleted += 1
2016-03-30 16:57:19 -04:00
courseProgress[levelID][userID].completed = true
dates = (s.get('dateFirstCompleted') || s.get('changed') for s in sessions)
courseProgress[levelID][userID].dateFirstCompleted = new Date(Math.max(dates...))
2016-03-30 16:57:19 -04:00
else # level started but not completed
courseProgress.completed = false
courseProgress[userID].completed = false
courseProgress[levelID].completed = false
courseProgress[levelID][userID].completed = false
Refactor and update teacher-dashboard This updates TeacherClassView and ActivateLicensesModal to use the new state-based rendering system, making it much snappier and less clunky feeling, and improving data consistency. Features also included in this: - Hover details for progress dots in TeacherClassView - ActivateLicensesModal has an "All Students" option and better handling when you switch classrooms in the dropdown - Unenrolled/Unassigned students are shown separately in Course Progress and can be enrolled/assigned from there. Add Back to Classes button on demo-request submitted view Delete temporary patch file Show unenrolled students separately in Course Progress (incomplete) Migrate TeacherClassView to use orchestrator-style events, add unassigned students section, replace bootstrap tabs with state-based tabs Convert missed instance variables to be in @state Fix merge errors (in progress) Convert a bunch of stuff to use state and events (removing student needs fixing) Fix up modal interactions, some bugs Switch state to be a Model, sync up course dropdowns Convert student sorting to use state model Add hover tooltips to TeacherClassView Students tab Don't keep tooltip open when you mouse into it Add dateFirstCompleted and Course Progress tooltips Course Overview progress tooltips Refactor ActivateLicensesModal Refactors: Uses state object for view state Passes back the updated users in 'redeem-users' event instead of modifying given collection Features: Add 'All Students' dropdown option Don't forget checked students if you change classroom from dropdown, but only enroll the ones visible when you click "Enroll (n) Students" Separate enrolled students; improve style Rearrange error text Disable enroll-students button when none are selected Remove console.logs Move style-flat variables to another file This prevents .style-flat from being copied in multiple times to the resulting CSS. Show Unarchive button when on the page for an archived class Move text to en.coffee Only sort students on first classroom sync Fix merge error Handle sessions missing completion date in view logic instead of migration script Listen to classroom sync more than once in case it gets unarchived
2016-04-19 16:44:48 -04:00
courseProgress[levelID].dateFirstCompleted = null
courseProgress[levelID][userID].dateFirstCompleted = null
2016-03-30 16:57:19 -04:00
_.assign(progressData, progressMixin)
return progressData
courseLabelsArray: (courses) ->
labels = []
courseLabelIndexes = CS: 0, GD: 0, WD: 0
for course in courses
acronym = switch
when /game-dev/.test(course.get('slug')) then 'GD'
when /web-dev/.test(course.get('slug')) then 'WD'
else 'CS'
labels.push acronym + ++courseLabelIndexes[acronym]
labels
2016-03-30 16:57:19 -04:00
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