mirror of
https://github.com/codeninjasllc/codecombat.git
synced 2024-11-25 00:28:31 -05:00
3d705e5d70
Fix link to /teachers/classes (fixes bugquest#20) Fix edit button color/icon (bugquest#23) Fix bugquest#34 Fix password input width (bugquest#33) Center new pasword text Fix teacher password reset endpoint (bugquest#4) Refactor+use NewHomeView logic for user page button (Fixes bugquest#2) Refactor teacher-password-reset endpoint This makes it much easier to prevent collisions with other logic when PUTing new User attributes. Add regression test for converting to teacher account Fix email verified links, require login (fix bugquest#16) Fix me having stale emailVerified value (Fixes bugquest#40) Don't show JoinClassModal to students Add paragraph to JoinClassModal (fixes bugquest#14) Update change-password label text (fixes bugquest#30) Fix prompting for login on Account Settings page (bugquest #10) Show validation errors for teacher password reset (bugquest#36) Show yellow progress dot in My Classes if anyone has started (bugquest#55) Remove confusing text (bugquest#100)
213 lines
10 KiB
CoffeeScript
213 lines
10 KiB
CoffeeScript
Levels = require 'collections/Levels'
|
|
|
|
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
|
|
calculateDots: (classrooms, courses, courseInstances) ->
|
|
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, withoutLadderLevels: true})
|
|
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) ->
|
|
session.get('creator') is userID and session.get('level').original is level.get('original')
|
|
# sessionMap[userID][level].completed()
|
|
session?.completed()
|
|
if _.every levelCompletes
|
|
instance.numCompleted += 1
|
|
|
|
calculateEarliestIncomplete: (classroom, courses, courseInstances, students) ->
|
|
# 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, withoutLadderLevels: true})
|
|
for level, levelIndex in levels.models
|
|
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
|
|
|
|
calculateLatestComplete: (classroom, courses, courseInstances, students) ->
|
|
# 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, withoutLadderLevels: true})
|
|
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) ->
|
|
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
|
|
levels = classroom.getLevels({courseID: course.id, withoutLadderLevels: true})
|
|
|
|
for level in levels.models
|
|
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
|
|
|
|
calculateAllProgress: (classrooms, courses, courseInstances, students) ->
|
|
# 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
|
|
|
|
levels = classroom.getLevels({courseID: course.id, withoutLadderLevels: true})
|
|
for level in levels.models
|
|
levelID = level.get('original')
|
|
progressData[classroom.id][course.id][levelID] = {
|
|
completed: students.size() > 0,
|
|
started: false
|
|
numStarted: 0
|
|
# numCompleted: 0
|
|
}
|
|
|
|
for user in students.models
|
|
userID = user.id
|
|
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) ->
|
|
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
|
|
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
|
|
|
|
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
|
|
courseProgress[levelID][userID].lastPlayed = new Date(session.get('changed'))
|
|
courseProgress[levelID].numStarted += 1
|
|
|
|
if session?.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'))
|
|
else # level started but not completed
|
|
courseProgress.completed = false
|
|
courseProgress[userID].completed = false
|
|
courseProgress[levelID].completed = false
|
|
courseProgress[levelID][userID].completed = false
|
|
courseProgress[levelID].dateFirstCompleted = null
|
|
courseProgress[levelID][userID].dateFirstCompleted = null
|
|
|
|
_.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
|