2015-11-03 19:41:06 -05:00
|
|
|
CocoModel = require './CocoModel'
|
|
|
|
schema = require 'schemas/models/classroom.schema'
|
2016-06-26 16:51:14 -04:00
|
|
|
utils = require '../core/utils'
|
2016-05-11 17:39:26 -04:00
|
|
|
User = require 'models/User'
|
2015-11-03 19:41:06 -05:00
|
|
|
|
|
|
|
module.exports = class Classroom extends CocoModel
|
|
|
|
@className: 'Classroom'
|
|
|
|
@schema: schema
|
|
|
|
urlRoot: '/db/classroom'
|
2016-06-26 16:51:14 -04:00
|
|
|
|
2016-03-30 16:57:19 -04:00
|
|
|
initialize: () ->
|
|
|
|
@listenTo @, 'change:aceConfig', @capitalizeLanguageName
|
|
|
|
super(arguments...)
|
2016-06-26 16:51:14 -04:00
|
|
|
|
2016-05-11 17:39:26 -04:00
|
|
|
parse: (obj) ->
|
|
|
|
if obj._id
|
|
|
|
# It's just the classroom object
|
|
|
|
return obj
|
|
|
|
else
|
|
|
|
# It's a compound response with other stuff too
|
|
|
|
@owner = new User(obj.owner)
|
|
|
|
return obj.data
|
2016-06-26 16:51:14 -04:00
|
|
|
|
2016-03-30 16:57:19 -04:00
|
|
|
capitalizeLanguageName: ->
|
|
|
|
language = @get('aceConfig')?.language
|
|
|
|
@capitalLanguage = utils.capitalLanguages[language]
|
2015-11-23 11:46:08 -05:00
|
|
|
|
|
|
|
joinWithCode: (code, opts) ->
|
|
|
|
options = {
|
2016-05-11 17:39:26 -04:00
|
|
|
url: @urlRoot + '/~/members'
|
2015-11-23 11:46:08 -05:00
|
|
|
type: 'POST'
|
|
|
|
data: { code: code }
|
2016-05-11 17:39:26 -04:00
|
|
|
success: => @trigger 'join:success'
|
|
|
|
error: => @trigger 'join:error'
|
|
|
|
}
|
|
|
|
_.extend options, opts
|
|
|
|
@fetch(options)
|
2016-06-26 16:51:14 -04:00
|
|
|
|
2016-05-11 17:39:26 -04:00
|
|
|
fetchByCode: (code, opts) ->
|
|
|
|
options = {
|
|
|
|
url: _.result(@, 'url')
|
|
|
|
data: { code: code, "with-owner": true }
|
2015-11-23 11:46:08 -05:00
|
|
|
}
|
|
|
|
_.extend options, opts
|
2015-12-02 14:56:38 -05:00
|
|
|
@fetch(options)
|
2016-06-26 16:51:14 -04:00
|
|
|
|
|
|
|
getLevelNumber: (levelID, defaultNumber) ->
|
|
|
|
unless @levelNumberMap
|
|
|
|
@levelNumberMap = {}
|
|
|
|
for course in @get('courses') ? []
|
|
|
|
levels = []
|
|
|
|
for level in course.levels when level.original
|
|
|
|
levels.push({key: level.original, practice: level.practice ? false})
|
|
|
|
_.assign(@levelNumberMap, utils.createLevelNumberMap(levels))
|
|
|
|
@levelNumberMap[levelID] ? defaultNumber
|
|
|
|
|
2015-12-02 14:56:38 -05:00
|
|
|
removeMember: (userID, opts) ->
|
|
|
|
options = {
|
|
|
|
url: _.result(@, 'url') + '/members'
|
|
|
|
type: 'DELETE'
|
|
|
|
data: { userID: userID }
|
|
|
|
}
|
|
|
|
_.extend options, opts
|
2016-03-30 16:57:19 -04:00
|
|
|
@fetch(options)
|
2016-05-20 17:52:04 -04:00
|
|
|
|
|
|
|
setStudentPassword: (student, password, options) ->
|
|
|
|
classroomID = @.id
|
|
|
|
$.ajax {
|
|
|
|
url: "/db/classroom/#{classroomID}/members/#{student.id}/reset-password"
|
|
|
|
method: 'POST'
|
|
|
|
data: { password }
|
|
|
|
success: => @trigger 'save-password:success'
|
|
|
|
error: (response) => @trigger 'save-password:error', response.responseJSON
|
|
|
|
}
|
2016-06-26 16:51:14 -04:00
|
|
|
|
2016-04-13 12:54:24 -04:00
|
|
|
getLevels: (options={}) ->
|
2016-07-16 00:57:04 -04:00
|
|
|
# options: courseID, withoutLadderLevels, projectLevels
|
2016-04-13 12:54:24 -04:00
|
|
|
Levels = require 'collections/Levels'
|
|
|
|
courses = @get('courses')
|
|
|
|
return new Levels() unless courses
|
|
|
|
levelObjects = []
|
|
|
|
for course in courses
|
|
|
|
if options.courseID and options.courseID isnt course._id
|
|
|
|
continue
|
|
|
|
levelObjects.push(course.levels)
|
|
|
|
levels = new Levels(_.flatten(levelObjects))
|
|
|
|
if options.withoutLadderLevels
|
|
|
|
levels.remove(levels.filter((level) -> level.isLadder()))
|
2016-07-16 00:57:04 -04:00
|
|
|
if options.projectLevels
|
2016-07-16 02:26:43 -04:00
|
|
|
levels.remove(levels.filter((level) -> level.get('shareable') isnt 'project'))
|
2016-04-13 12:54:24 -04:00
|
|
|
return levels
|
2016-06-26 16:51:14 -04:00
|
|
|
|
2016-04-13 12:54:24 -04:00
|
|
|
getLadderLevel: (courseID) ->
|
|
|
|
Levels = require 'collections/Levels'
|
|
|
|
courses = @get('courses')
|
|
|
|
course = _.findWhere(courses, {_id: courseID})
|
|
|
|
return unless course
|
|
|
|
levels = new Levels(course.levels)
|
|
|
|
return levels.find (l) -> l.isLadder()
|
|
|
|
|
|
|
|
statsForSessions: (sessions, courseID) ->
|
|
|
|
return null unless sessions
|
|
|
|
sessions = sessions.models or sessions
|
|
|
|
arena = @getLadderLevel(courseID)
|
2016-06-26 16:51:14 -04:00
|
|
|
courseLevels = @getLevels({courseID: courseID, withoutLadderLevels: true})
|
|
|
|
levelSessionMap = {}
|
|
|
|
levelSessionMap[session.get('level').original] = session for session in sessions
|
|
|
|
currentIndex = -1
|
|
|
|
lastStarted = null
|
|
|
|
levelsTotal = 0
|
|
|
|
levelsLeft = 0
|
|
|
|
lastPlayed = null
|
|
|
|
playtime = 0
|
|
|
|
levels = []
|
|
|
|
for level, index in courseLevels.models
|
|
|
|
levelsTotal++ unless level.get('practice')
|
|
|
|
complete = false
|
|
|
|
if session = levelSessionMap[level.get('original')]
|
|
|
|
complete = session.get('state').complete ? false
|
|
|
|
playtime += session.get('playtime') ? 0
|
|
|
|
lastPlayed = level
|
|
|
|
if complete
|
|
|
|
currentIndex = index
|
|
|
|
else
|
|
|
|
lastStarted = level
|
|
|
|
levelsLeft++ unless level.get('practice')
|
|
|
|
else if not level.get('practice')
|
|
|
|
levelsLeft++
|
|
|
|
levels.push
|
|
|
|
practice: level.get('practice') ? false
|
|
|
|
complete: complete
|
|
|
|
lastPlayed = lastStarted ? lastPlayed
|
|
|
|
needsPractice = false
|
|
|
|
nextIndex = 0
|
|
|
|
if currentIndex >= 0
|
|
|
|
currentLevel = courseLevels.models[currentIndex]
|
|
|
|
currentPlaytime = levelSessionMap[currentLevel.get('original')]?.get('playtime') ? 0
|
|
|
|
needsPractice = utils.needsPractice(currentPlaytime, currentLevel.get('practiceThresholdMinutes'))
|
|
|
|
nextIndex = utils.findNextLevel(levels, currentIndex, needsPractice)
|
|
|
|
nextLevel = courseLevels.models[nextIndex]
|
|
|
|
nextLevel ?= _.find courseLevels.models, (level) -> not levelSessionMap[level.get('original')]?.get('state')?.complete
|
|
|
|
|
|
|
|
stats =
|
|
|
|
levels:
|
|
|
|
size: levelsTotal
|
|
|
|
left: levelsLeft
|
|
|
|
done: levelsLeft is 0
|
|
|
|
numDone: levelsTotal - levelsLeft
|
|
|
|
pctDone: (100 * (levelsTotal - levelsLeft) / levelsTotal).toFixed(1) + '%'
|
|
|
|
lastPlayed: lastPlayed
|
|
|
|
next: nextLevel
|
|
|
|
first: courseLevels.first()
|
|
|
|
arena: arena
|
|
|
|
playtime: playtime
|
|
|
|
stats
|
2016-04-13 12:54:24 -04:00
|
|
|
|
|
|
|
fetchForCourseInstance: (courseInstanceID, options={}) ->
|
2016-04-27 18:36:16 -04:00
|
|
|
return unless courseInstanceID
|
2016-04-13 12:54:24 -04:00
|
|
|
CourseInstance = require 'models/CourseInstance'
|
|
|
|
courseInstance = if _.isString(courseInstanceID) then new CourseInstance({_id:courseInstanceID}) else courseInstanceID
|
|
|
|
options = _.extend(options, {
|
|
|
|
url: _.result(courseInstance, 'url') + '/classroom'
|
|
|
|
})
|
2016-04-27 18:36:16 -04:00
|
|
|
@fetch(options)
|
2016-05-06 16:28:19 -04:00
|
|
|
|
|
|
|
inviteMembers: (emails, options={}) ->
|
|
|
|
options.data ?= {}
|
2016-06-06 16:43:41 -04:00
|
|
|
options.data.emails = emails
|
2016-05-06 16:28:19 -04:00
|
|
|
options.url = @url() + '/invite-members'
|
|
|
|
options.type = 'POST'
|
|
|
|
@fetch(options)
|
2016-07-21 18:15:59 -04:00
|
|
|
|
|
|
|
updateCourses: (options={}) ->
|
|
|
|
options.url = @url() + '/update-courses'
|
|
|
|
options.type = 'POST'
|
|
|
|
@fetch(options)
|