Fix teacher sessionless play; uses default campaign levels

Fix typo

Fix race condition with loading next level

Return an empty object for next level instead of an error;
Supermodel has a race condition when some of the models fail to load,
when we override an error response as "success".

Fix next level spec

Remove comment per Scott's request
This commit is contained in:
phoenixeliot 2016-04-27 15:36:16 -07:00
parent 135f7f05ad
commit 91fa467251
9 changed files with 72 additions and 14 deletions

View file

@ -82,9 +82,10 @@ module.exports = class Classroom extends CocoModel
return stats
fetchForCourseInstance: (courseInstanceID, options={}) ->
return unless courseInstanceID
CourseInstance = require 'models/CourseInstance'
courseInstance = if _.isString(courseInstanceID) then new CourseInstance({_id:courseInstanceID}) else courseInstanceID
options = _.extend(options, {
url: _.result(courseInstance, 'url') + '/classroom'
})
@fetch(options)
@fetch(options)

View file

@ -252,6 +252,9 @@ module.exports = class Level extends CocoModel
isLadder: ->
return @get('type')?.indexOf('ladder') > -1
fetchNextForCourse: (levelOriginalID, courseInstanceID, options={}) ->
options.url = "/db/course_instance/#{courseInstanceID}/levels/#{levelOriginalID}/next"
@fetch(options)
fetchNextForCourse: ({ levelOriginalID, courseInstanceID, courseID }, options={}) ->
if courseInstanceID
options.url = "/db/course_instance/#{courseInstanceID}/levels/#{levelOriginalID}/next"
else
options.url = "/db/course/#{courseID}/levels/#{levelOriginalID}/next"
@fetch(options)

View file

@ -69,7 +69,7 @@ module.exports = class User extends CocoModel
isSessionless: ->
# TODO: Fix old users who got mis-tagged as teachers
# TODO: Should this just be isTeacher, eventually?
me.isTeacher() and utils.getQueryVariable('course', false)
Boolean(me.isTeacher() and utils.getQueryVariable('course', false))
setRole: (role, force=false) ->
return if me.isAdmin()

View file

@ -29,9 +29,9 @@ module.exports = class CourseVictoryModal extends ModalView
@newItems = new ThangTypes()
@newHeroes = new ThangTypes()
@classroom = new Classroom()
@supermodel.trackRequest(@classroom.fetchForCourseInstance(@courseInstanceID))
if @courseInstanceID
@classroom = new Classroom()
@supermodel.trackRequest(@classroom.fetchForCourseInstance(@courseInstanceID))
@achievements = options.achievements
if not @achievements
@achievements = new Achievements()
@ -43,7 +43,7 @@ module.exports = class CourseVictoryModal extends ModalView
@playSound 'victory'
@nextLevel = new Level()
@nextLevelRequest = @supermodel.trackRequest @nextLevel.fetchNextForCourse(@level.get('original'), @courseInstanceID)
@nextLevelRequest = @supermodel.trackRequest @nextLevel.fetchNextForCourse({ levelOriginalID: @level.get('original'), @courseInstanceID, @courseID })
@course = options.course
if @courseID and not @course

View file

@ -96,7 +96,7 @@ module.exports =
throw new errors.NotFound('Level original ObjectId not found in Classroom courses')
if not nextLevelOriginal
throw new errors.NotFound('No more levels in that course')
res.status(200).send({})
dbq = Level.findOne({original: mongoose.Types.ObjectId(nextLevelOriginal)})
dbq.sort({ 'version.major': -1, 'version.minor': -1 })
@ -122,4 +122,4 @@ module.exports =
classroom = classroom.toObject({req: req})
res.status(200).send(classroom)
res.status(200).send(classroom)

View file

@ -0,0 +1,51 @@
errors = require '../commons/errors'
wrap = require 'co-express'
database = require '../commons/database'
mongoose = require 'mongoose'
Campaign = require '../models/Campaign'
CourseInstance = require '../models/CourseInstance'
Classroom = require '../models/Classroom'
Course = require '../models/Course'
User = require '../models/User'
Level = require '../models/Level'
parse = require '../commons/parse'
module.exports =
fetchNextLevel: wrap (req, res) ->
levelOriginal = req.params.levelOriginal
if not database.isID(levelOriginal)
throw new errors.UnprocessableEntity('Invalid level original ObjectId')
course = yield database.getDocFromHandle(req, Course)
if not course
throw new errors.NotFound('Course Instance not found.')
campaign = yield Campaign.findById course.get('campaignID')
if not campaign
throw new errors.NotFound('Campaign not found.')
levels = _.values(campaign.get('levels'))
levels = _.sortBy(levels, 'campaignIndex')
nextLevelOriginal = null
foundLevelOriginal = false
for level, index in levels
if level.original.toString() is levelOriginal
foundLevelOriginal = true
nextLevelOriginal = levels[index+1]?.original
break
if not foundLevelOriginal
throw new errors.NotFound('Level original ObjectId not found in that course')
if not nextLevelOriginal
res.status(200).send({})
dbq = Level.findOne({original: mongoose.Types.ObjectId(nextLevelOriginal)})
dbq.sort({ 'version.major': -1, 'version.minor': -1 })
dbq.select(parse.getProjectFromReq(req))
level = yield dbq
level = level.toObject({req: req})
res.status(200).send(level)

View file

@ -5,6 +5,7 @@ module.exports =
campaigns: require './campaigns'
codelogs: require './codelogs'
courseInstances: require './course-instances'
courses: require './courses'
files: require './files'
named: require './named'
patchable: require './patchable'

View file

@ -59,6 +59,7 @@ module.exports.setup = (app) ->
Course = require '../models/Course'
app.get('/db/course', mw.rest.get(Course))
app.get('/db/course/:handle', mw.rest.getByHandle(Course))
app.get('/db/course/:handle/levels/:levelOriginal/next', mw.courses.fetchNextLevel)
app.get('/db/course_instance/:handle/levels/:levelOriginal/next', mw.courseInstances.fetchNextLevel)
app.post('/db/course_instance/:handle/members', mw.auth.checkLoggedIn(), mw.courseInstances.addMembers)

View file

@ -315,9 +315,10 @@ describe 'GET /db/course_instance/:handle/levels/:levelOriginal/next', ->
expect(res.body.original).toBe(@levelB.original.toString())
done()
it 'returns 404 if the given level is the last level in its course', utils.wrap (done) ->
it 'returns empty object if the given level is the last level in its course', utils.wrap (done) ->
[res, body] = yield request.getAsync { uri: utils.getURL("/db/course_instance/#{@courseInstanceA.id}/levels/#{@levelB.id}/next"), json: true }
expect(res.statusCode).toBe(404)
expect(res.statusCode).toBe(200)
expect(res.body).toEqual({})
done()
it 'returns 404 if the given level is not in the course instance\'s course', utils.wrap (done) ->
@ -363,4 +364,4 @@ describe 'GET /db/course_instance/:handle/classroom', ->
yield utils.loginUser @user
[res, body] = yield request.getAsync(@url, {json: true})
expect(res.statusCode).toBe(403)
done()
done()